在Rust中,若是要進行屏幕輸出,或者寫入到文件中,須要對數據進行格式化。這一篇總結一下它所支持的幾種格式化方式。css
這篇文章參考瞭如下官方文檔,不過,按照個人風格,我仍是會突出於C#語言的比較,這樣可能更好懂一些。html
http://rustbyexample.com/hello/print.htmlapp
http://doc.rust-lang.org/std/fmt/ui
http://rustbyexample.com/hello/print/print_debug.htmlthis
http://rustbyexample.com/hello/print/print_display.htmlspa
首先,有三個常見的宏,能夠用來作格式化debug
format!
: write formatted text to String
這個宏能夠將一個文本格式化成String類型(可變字符串,在堆上面分配空間),相似於C#中的String.Format方法。 print!
: same as format!
but the text is printed to the console. 和format!這個宏功能同樣,只不過是輸出到屏幕上。相似於C#中的Console.Write方法。 println!
: same as print!
but a newline is appended. 同上,只不過添加了換行符,相似於C#中的Console.WriteLine方法。
既然搞清楚了這三個宏,與C#中有關實現方式的關係,其實就很好理解了。通常這類方法,均可以比較方便地組合字符串,經過佔位符這種東西。在C#中,用{0}表示第一個佔位符,用{1}表示第二個佔位符,依次類推。code
https://msdn.microsoft.com/zh-cn/library/system.string.format(v=vs.110).aspxorm
https://msdn.microsoft.com/zh-cn/library/txafckwd(v=vs.110).aspxhtm
可是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. }
知道了如何作格式化,下面要討論一個問題:具體對象到底怎麼實現本身的字符串表現形式的呢?其實,以前我已經略微介紹到了這個問題
從上面的例子中,咱們知道,要將一個對象做爲一個字符串輸出的話,就須要對其進行轉換。咱們在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方法,若是沒有,則會報告錯誤注意,除了這兩種形式,還有其餘一些格式化輸出方式
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,會成功 }
輸出結果以下