在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,會失敗 }
這個例子連編譯都不會通過
那么,如何實現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,會成功 }
那么,它是怎樣輸出的呢?
實際上就很類似於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,會成功 }
輸出結果如下