rust输入输出

这篇具有很好参考价值的文章主要介绍了rust输入输出。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、获取命令行参数

很多语言获取命令行参数,是通过主函数的参数获得的。
但Rust主函数是个无参数函数,命令行参数只能通过std::env::args()函数获得。
std::env::args()返回一个迭代器,其中包含了程序名和后面所有参数。

实例

fn main() {
    let args = std::env::args();
    for arg in args {
        println!("{}", arg);
    }
}
运行结果:
/home/yt/src/foo/target/debug/foo

可以在launch.json中的"args": []设置命令行参数。
我们将它改成"args": [“first”, “second”] ,然后保存、再次运行刚才的程序,运行结果:

/home/yt/src/foo/target/debug/foo
first
second

二、输入输出

Rust标准库通过两个特质组织输入输出
Read特质包含了许多方法用于读取数据
Write特质包含了许多方法用于写入数据

Read特质

fn read(&mut self, buf: &mut [u8]) -> Result<usize>
读取一些字节到指定的缓冲区中,返回读取的字节数
fn read_to_string(&mut self, buf: &mut String) -> Result<usize>
读取所有字节,直到EOF为止,然后将它们追加到 buf

Write特质

fn write(&mut self, buf: &[u8]) -> Result<usize>
write()  方法把参数  buf写入输出流。返回Result枚举,如果成功则返回写入的字节数。
fn write_fmt(&mut self, args: Arguments<'_>) -> Result<()>
将格式化的字符串写入输出流,返回遇到的任何错误

(一)标准输入
std::io::stdin()函数返回一个std::io::Stdin的实例,这是一个结构体,代表标准输入流。
结构体Stdin虽然实现了Read特性,但还实现了一个read_line方法,我们常用这个方法,而不是Read特性的方法。

pub fn read_line(&self, buf: &mut String) -> Result<usize>
read_line方法读取一行字符串(包括换行符)追加到buf,返回值是读取的字节数。
因为read_line会读取末尾的换行符,所以一般在读入buf之后,要调用buf的trim方法,将换行符删除。

实例

use std::io;
fn main() {
     let mut str_buf = String::new();
     io::stdin().read_line(&mut str_buf).expect("Failed to read line.");
     println!("Your input line is \n{}", str_buf);
}

实例

fn main(){
     let mut line = String::new();
     println!("请输入你的名字:");
     let b1 = std::io::stdin().read_line(&mut line).unwrap();
     println!("你好 , {}", line);
     println!("读取的字节数为:{}", b1);
}
输出结果如下
请输入你的名字:
简单教程
你好 , 简单教程
读取的字节数为:13

注意:
目前Rust标准库还没有读取数字或格式化数据的方法,我们只能读取字符串,然后自己把字符串转换成数字,通常是使用parse把字符串转成数字。参考rust类型转换

实例

一行只有一个数
let mut buf = String::new();
io::stdin().read_line(&mut buf).unwrap();
let num1: i32 = buf.trim().parse().unwrap();

一行有多个数
let mut buf = String::new();
io::stdin().read_line(&mut buf).unwrap();
let mut nums = buf.split_whitespace();
let num1: f64 = nums.next().unwrap().parse().unwrap();
let num2: f64 = nums.next().unwrap().parse().unwrap();
let num3: f64 = nums.next().unwrap().parse().unwrap();

读入数组
let mut buff = String::new();
io::stdin().read_line(&mut buff).unwrap();
let ns: Vec<i32> = buff.split_whitespace().map(|x| x.parse().unwrap()).collect();
for v in ns {
     print!("{} ", v);
}

(二)标准输出
std::io::stdout()会返回一个std::io::Stdout的实例,这是个结构体,表示标准输出流。
结构体Stdout实现了Write特质

实例

use std::io::Write;
fn main() {
     let b1 = std::io::stdout().write("简单教程 ".as_bytes()).unwrap();
     let b2 = std::io::stdout().write(String::from("www.twle.cn").as_bytes()).unwrap();
     std::io::stdout().write(format!("\n写入的字节数为:{}\n",(b1+b2)).as_bytes()).unwrap();
}
输出结果如下
简单教程www.twle.cn
写入的字节数为:24

write_fmt方法通常与format_args!()搭配使用。应优先使用write!()宏

std::io::stdout().write_fmt(format_args!("{:.*}", 2, 1.234567)).unwrap();
write!(std::io::stdout(), "{:.*}", 2, 1.234567).unwrap();

(三)格式化输出
std::fmt 模块定义了一系列宏,包括:
format! 从格式化文本创建字符串。
print! 与format! 类似,但将文本输出到标准输出。
println! 与print! 类似,但输出结果追加一个换行符。
eprint! 与print! 类似,但将文本输出到标准错误。
eprintln! 与eprint! 类似,但输出结果追加一个换行符。
write! 第一个参数是 &mut io::Write或 &mut fmt::Write,后面参数与format!一样
writeln! 与write!相同,但追加了一个换行符

以println!为例
第一个参数是格式字符串,它必须是字符串字面量
后面是参数列表,依次对应格式字符串中的"占位符",这一点与C语言中的printf函数很相似。但是,Rust的占位符是{}。

占位符的完整格式为

'{' [ argument] [ ':' [[fill]align][sign]['#']['0'][width]['.' precision]type ]'}'

1.argument
分两种
(1)位置参数
除了依次替换占位符之外,还能在占位符中指定位置,表示让此位置的参数去替换占位符,例如 {1},表示用第二个参数替换该占位符(索引从0开始)

println!("{}{}", 1, 2); // =>"12"
println!("{1}{0}", 1, 2); // =>"21"

一旦开始将两种类型的位置说明符混合在一起,事情就会变得有些棘手

println!("{1} {} {0} {}", 1, 2); // => "2 1 1 2"

(2)命名参数
还可以为参数指定名称,带名称的参数必须放在不带名称参数的后面

println!("{argument}", argument = "test"); // => "test"
println!("{name} {}", 1, name = 2); // => "2 1"
println!("{a} {c} {b}", a="a", b='b', c=3); // => "a 3 b"

如果命名参数没有出现在参数列表中,println! 将引用当前作用域中的同名变量

let argument = 2 + 2;
println!("{argument}"); // => "4"

2.总宽度width
总宽度表示输出的总长度,如果实际长度不够,则要填充和对齐
有两种方法指定宽度

N: N 是整数。
N$:N是位置参数或命名参数

实例

println!("Hello {:5}!", "x");     //Hello x    !
println!("Hello {:1$}!", "x", 5);     //Hello x    !
println!("Hello {1:0$}!", 5, "x");     //Hello x    !
println!("Hello {:width$}!", "x", width = 5);     //Hello x    !
let width = 5;
println!("Hello {:width$}!", "x");     //Hello x    !

3.精度.precision
如果是整数,则忽略
如果是小数,精度表示小数点后面位数。默认是6
如果是字符串,精度表示字符数。如果实际大于精度,后面的字符会截掉
有三种可能的方法来指定精度:

.N:N是整数。
.N$:N是位置参数或命名参数
.*:.* 表示第一个参数表示精度,第二个参数才是要输出的值

实例

let v = 3.1415926;
println!("{:.2}", v);     // 保留小数点后两位 => 3.14
println!("{:.0}", v);     // 不带小数 => 3
println!("{:.1$}", v, 4);     // 通过位置参数来设定精度 => 3.1416,相当于{:.4}
println!("{:.prec$}", v, prec=4);     // 通过命名参数来设定精度 => 3.1416,相当于{:.4}
let s = "hi你好";
println!("{:.3}", s);     // 保留字符串前三个字符 => hi你
println!("Hello {:.*}", 3, "abcdefg");     // {:.*}接收两个参数,第一个是精度,第二个是要输出的值 => Hello abc

4.填充fill
参数位数不够时,要填充。默认填充空格
实例

println!("Hello {:*>5}!", "x");     //Hello ****x!
println!("Hello {:.<5}!", "x");     //Hello x....!
println!("Hello {:0<5}!", "x");     //Hello x0000!

5.对齐align
字符串默认默认左对齐,数字是右对齐

< 左对齐
^ 居中对齐
> 右对齐
println!("Hello {:<5}!", "x");     //Hello x    !
println!("Hello {:^5}!", "x");     //Hello   x  !
println!("Hello {:>5}!", "x");     //Hello     x!

6.Sign/#/0
sign可以是+或者-
+表示数字应打印符号。默认情况下从不打印正号,仅打印负号。 使用+之后,就会打印正号。
-当前未使用
#单独使用无效,必须与type一起使用。见type
0表示整数使用0填充,并且是符号感知的。像 {:08} 这样的格式将为整数 1 产生 00000001,而相同格式将为整数 -1 产生 -0000001。 请注意,负版本的零比正版本的少零。 请注意,填充零总是放在符号之后和数字之前。当与 # 标志一起使用时,将应用类似的规则:在前缀之后但在数字之前插入填充零。 前缀包括在总宽度中。这个0是放在对齐之后的,与对齐之前的0是不同的。

实例

println!("Hello {:0<5}!", 5); //Hello 50000!
println!("Hello {:<05}!", 5); //Hello 00005!
println!("Hello {:0<5}!", -5); // 负号也要占用一位宽度 => Hello -5000!
println!("Hello {:<05}!", -5); // 负号也要占用一位宽度 => Hello -0005!
println!("Hello {:+}!", 5);     // 显式的输出正号 => Hello +5!
println!("{:#x}!", 27);     //0x1b!
println!("{:#010x}!", 27);     //0x0000001b!

7.类型type
nothing ⇒ Display,以Display 格式打印
? ⇒ Debug,以Debug 格式打印
x? ⇒ Debug ,以Debug 格式打印,整数以小写十六进制
X? ⇒ Debug ,以Debug 格式打印,整数以大写十六进制
o ⇒ Octal
x ⇒ LowerHex
X ⇒ UpperHex
p ⇒ Pointer
b ⇒ Binary
e ⇒ LowerExp
E ⇒ UpperExp

Display 格式打印
println!("{}", 27); // 十进制 => 27
println!("{:b}", 27); // 二进制 => 11011
println!("{:o}", 27); // 八进制 => 33
println!("{:x}", 27); // 小写十六进制 => 1b
println!("{:X}", 27); // 大写十六进制 => 1B

当前面有#时,添加前缀
println!("{:#}", 27); // 十进制 => 27
println!("{:#b}", 27); // 二进制 => 0b11011
println!("{:#o}", 27); // 八进制 => 0o33
println!("{:#x}", 27); // 小写十六进制 => 0x1b
println!("{:#X}", 27); // 大写十六进制 => 0x1B

以以Debug 格式打印
let v= vec![1, 2, 3, 10, 11, 12];
println!("{:?}", v);      //[1, 2, 3, 10, 11, 12]
println!("{:x?}", v);      //[1, 2, 3, a, b, c]
println!("{:X?}", v);      //[1, 2, 3, A, B, C]

当前面有#时,添加换行和缩进
let v= vec![1, 2, 3, 10, 11, 12];
println!("{:#?}", v);
println!("{:#x?}", v); 
println!("{:#X?}", v); 
打印结果如下
[
    1,
    2,
    3,
    10,
    11,
    12,
]
[
    0x1,
    0x2,
    0x3,
    0xa,
    0xb,
    0xc,
]
[
    0x1,
    0x2,
    0x3,
    0xA,
    0xB,
    0xC,
]

以科学计数法
println!("{:2e}", 1000000000); // => 1e9
println!("{:2E}", 1000000000); // => 1E9

以指针
let v= vec![1, 2, 3];
println!("{:p}", v.as_ptr()); // => 0x600002324050

8.转义
有时需要输出 {和},但这两个字符是特殊字符,需要转义:

{{ 转义为 {
}} 转义为 }
\" 转义为 "
println!(" Hello \"{{World}}\" ");     // => Hello "{World}"

9.Debug特性
要想以Debug格式打印,类型必须要实现了Debug特性才行。大多数Rust类型都实现了Debug特性,但是对于自定义类型,需要自己实现Debug特性。有一种实现Debug特性的简单方法,就是使用derive属性

#[derive(Debug)]
struct Person {
     name: String,
     age: u8
}
fn main() {
     let i = 3.1415926;
     let s = String::from("hello");
     let v = vec![1, 2, 3];
     let p = Person{name: "sunface".to_string(), age: 18};
     println!("{:?}, {:?}, {:?}, {:?}", i, s, v, p);
}

10.Display特性
要想以Display 格式打印,类型必须要实现了Display特性才行。实现了Display特征的Rust类型并不多,往往需要我们自己实现。为类型实现Display特性不像Debug一样能使用derive属性。

为自定义类型实现Display特征

struct Person {
     name: String,
     age: u8,
}
use std::fmt;
impl fmt::Display for Person {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
          write!(
              f,
              "大佬在上,请受我一拜,小弟姓名{},年芳{},家里无田又无车,生活苦哈哈",
              self.name, self.age
          )
     }
}
fn main() {
     let p = Person {
          name: "xx".to_string(),
          age: 18,
     };
     println!("{}", p);
}

为外部类型实现Display特性
由于孤儿原则,无法直接为外部类型实现外部特性,但是可以使用newtype解决此问题。

struct Array(Vec<i32>);
use std::fmt;
impl fmt::Display for Array {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
          write!(f, "数组是:{:?}", self.0)
     }
}
fn main() {
     let arr = Array(vec![1, 2, 3]);
     println!("{}", arr);
}

Array就是我们的newtype,它封装了Vec,为Array实现Display特性,相当于间接为Vec实现了Display。

三、文件读写

Rust文件读写文章来源地址https://www.toymoban.com/news/detail-732609.html

到了这里,关于rust输入输出的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 2.C语言——输入输出

    1.输入:getchar() 字面意思, 接收单个字符 ,使用方法 2.输出:putchar() 1.输入:scanf() 格式: scanf(“格式控制字符串”,地址列表); 如果格式符之间添加了空格,那么按照规则, 会忽略掉全部的空白符 直到遇到下一个不是空白符的字符 格式说明符 意义 %d 输入有符号的十进制数

    2024年02月19日
    浏览(38)
  • 6、C语言:输入与输出

    使用输入/输出库函数的每个源程序文件必须包含: 许多程序只从一个输入流中读取数据,并且只向一个输出流中输出数据。对于这样的程序,只需要使用函数getchar、putchar和printf实现输入/输出即可。 格式化输出——printf函数 函数printf在输出格式format的控制下,将其参数进行

    2024年02月01日
    浏览(46)
  • C语言——数据的输入输出

    C语言中没有专门的输入输出语句,C语言的输入输出是靠库函数来实现的。 格式: printf(“格式控制字符串”,输出列表); 功能: 按格式控制字符串规定的格式,向输出设备(一般为显示器)输出,输出列表中各输出项的值。 如: 格式控制:由双引号括起来的字符串,

    2024年02月12日
    浏览(39)
  • C语言入门篇——输入输出篇

    目录 1、printf()函数 1.1、printf()函数中的标记 1.2、输出最小宽度(width) 1.3、精度(.precision) 2、scanf()函数 2.1、scanf(“输入控制符”, 输入参数) 2.2、scanf(“输入控制符非输入控制符”, 输入参数); 2.3、字符串和转义字符 2.4、注意事项 printf()函数是C语言标准输出函数,用于将

    2024年02月04日
    浏览(40)
  • 【C语言基础】数据输入输出

    📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍 收藏 ⭐不迷路🙉 📢:内容若有错误,敬请留言 📝指正!原创文,转载请注明出处 数据输入的作用:

    2024年02月11日
    浏览(43)
  • C语言学习笔记:输入&输出

    ✨博文作者:烟雨孤舟 💖 喜欢的可以 点赞 收藏 关注哦~~ ✍️ 作者简介: 一个热爱大数据的学习者 ✍️ 笔记简介:作为大数据爱好者,以下是个人总结的学习笔记,如有错误,请多多指教! 目录 scanf和printf gets和puts getchar和putchar printf是格式化的输出函数,scanf是C语言的输

    2024年02月09日
    浏览(46)
  • C语言 链表输入输出数组

            链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一

    2024年02月08日
    浏览(47)
  • 【C语言】对文件的输入输出

    💗个人主页💗 ⭐个人专栏——C语言初步学习⭐ 💫点击关注🤩一起学习C语言💯💫 凡是用过计算机的人都不会对“文件”感到陌生,大多数人都接触过或使用过文件,例如: 写一篇文章把它存放到磁盘上以文件形式保存; 编写好一个程序,以文件形式保存在磁盘中; 用

    2024年02月08日
    浏览(41)
  • 多组的输入输出(C语言)

    当你想计算多组数字相加时,那就需要输入多个数字,在C语言中,一般一个scanf只能输入一组数据,那如何能同时输入多组数据呢? 例(一):  直接用while来解决,上代码: 例(二):     这个就更显而易见了,直接用while:  例(三):  例(四):     例(五):

    2024年02月08日
    浏览(34)
  • 高阶C语言|C语言文件管理--输入输出流

    我们前面已经介绍了结构体,也学习了通讯录,存在一个问题就是,每次通讯录程序退出,之前写好的信息都没了,下次进入通讯录,又得重新输入信息,这样的通讯录使用起来就很难受。那么怎样可以使数据保留下来,这里就涉及到了数据持久化的问题,数据持久化的方法

    2024年02月15日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包