在Rust中,如果要进行屏幕输出,或者写入到文件中,需要对数据进行格式化。这一篇总结一下它所支持的几种格式化方式。
这篇文章参考了以下官方文档,不过,按照我的风格,我还是会突出于C#语言的比较,这样可能更好懂一些。
http://rustbyexample.com/hello/print.html
http://doc.rust-lang.org/std/fmt/
http://rustbyexample.com/hello/print/print_debug.html
http://rustbyexample.com/hello/print/print_display.html
首先,有三个常见的宏,可以用来做格式化
-
format!
: write formatted text toString
这个宏可以将一个文本格式化成String类型(可变字符串,在堆上面分配空间),类似于C#中的String.Format方法。 -
print!
: same asformat!
but the text is printed to the console. 和format!这个宏功能一样,只不过是输出到屏幕上。类似于C#中的Console.Write方法。 -
println!
: same asprint!
but a newline is appended. 同上,只不过添加了换行符,类似于C#中的Console.WriteLine方法。
既然搞清楚了这三个宏,与C#中有关实现方式的关系,其实就很好理解了。一般这类方法,都可以比较方便地组合字符串,通过占位符这种东西。在C#中,用{0}表示第一个占位符,用{1}表示第二个占位符,依次类推。
https://msdn.microsoft.com/zh-cn/library/system.string.format(v=vs.110).aspx
https://msdn.microsoft.com/zh-cn/library/txafckwd(v=vs.110).aspx
但是Rust提供了一些自己的创新做法,它可以直接用空的占位符 {}(这个在C#中不允许的),也可以用带序号的占位符 {0},还直接带名称的占位符{name},同样,也支持在占位符里面指定特殊格式化的符号,例如{:?} 。 这里有一篇详细的介绍http://doc.rust-lang.org/std/fmt/
fn main() {
// In general, the `{}` will be automatically replaced with any
// arguments. These will be stringified.
println!("{} days", 31); // Without a suffix, 31 becomes an i32. You can change what type 31 is,
// with a suffix. // There are various optional patterns this works with. Positional
// arguments can be used.
println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob"); // As can named arguments.
println!("{subject} {verb} {predicate}",
predicate="over the lazy dog",
subject="the quick brown fox",
verb="jumps"); // Special formatting can be specified after a `:`.
println!("{} of {:b} people know binary, the other half don't", 1, 2); // It will even check to make sure the correct number of arguments are
// used.
println!("My name is {0}, {1} {0}", "Bond");
// FIXME ^ Add the missing argument: "James" // Create a structure which contains an `i32`. Name it `Structure`.
struct Structure(i32); // However, custom types such as this structure require more complicated
// handling. This will not work.
println!("This struct `{}` won't print...", Structure(3));
// FIXME ^ Comment out this line.
}
知道了如何做格式化,下面要讨论一个问题:具体对象到底怎么实现自己的字符串表现形式的呢?其实,之前我已经略微介绍到了这个问题
Rust初步(四):在rust中处理时间
从上面的例子中,我们知道,要将一个对象作为一个字符串输出的话,就需要对其进行转换。我们在C#中就是要实现ToString方法,在Rust里面,分别有两个方法Debug和Display方法。如果是元类型(Primitive Type),当然是没有问题的,基本上都已经实现了。
-
fmt::Debug
: Uses the{:?}
marker. Format text for debugging purposes. 如果我们的占位符使用{:?},默认会调用对象的Debug方法,如果没有,则会报告错误 -
fmt::Display
: Uses the{}
marker. Format text in a more elegant, user friendly fashion.如果我们的占位符使用{},,默认会调用对象的Display方法,如果没有,则会报告错误
注意,除了这两种形式,还有其他一些格式化输出方式
-
unspecified ->
Display
-
?
->Debug
-
o
–>Octal //8进制
-
x
–>LowerHex //16进制
-
X
->UpperHex
-
p
–>Pointer
-
b
–>Binary //二进制
-
e
->LowerExp
-
E
->UpperExp
下面考虑一个例子,来加深理解
struct Point{ //自定义一个结构体
x:i32,
y:i32
} fn main() {
let p = Point{x:3,y:5};
println!("{}",p.x);//打印x,这会成功
println!("{:?}",p);//直接打印整个结构体,因为没有实现Debug,会失败
println!("{}",p);//直接打印整个结构体,因为没有实现Display,会失败
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
这个例子连编译都不会通过
那么,如何实现Debug和Display呢?
Debug相对来说很简单,只要声明一下即可
#[derive(Debug)]
struct Point{ //自定义一个结构体
x:i32,
y:i32
} fn main() {
let p = Point{x:3,y:5};
println!("{}",p.x);//打印x,这会成功
println!("{:?}",p);//直接打印整个结构体,因为已经实现Debug,会成功 }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
那么,它是怎样输出的呢?
实际上就很类似于C#中所有Object的默认实现(ToString)
相比而言,Display是需要手工来实现的,大致如下
use std::fmt; #[derive(Debug)]
struct Point{ //自定义一个结构体
x:i32,
y:i32
} impl fmt::Display for Point{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "x为{},y为{}", self.x,self.y)
} } fn main() {
let p = Point{x:3,y:5};
println!("{}",p);//直接打印整个结构体,因为已经实现Debug,会成功 }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
输出结果如下