边做边学Rust之Hello World
2015-11-16 08:45
731 查看
1. Hello World
这是一个传统Hello World程序的源码:// This is a comment, and will be ignored by the compiler
// You can test this code by clicking the "Run" button over there ->
// or if prefer to use your keyboard, you can use the "Ctrl + Enter" shortcut
// This code is editable, feel free to hack it!
// You can always return to the original code by clicking the "Reset" button ->
// This is the main function
fn main() {
// The statements here will be executed when the compiled binary is called
// Print text to the console
println!("Hello World!");
}
println! 是一个将信息打印到控制台上的宏。
一个二进制可执行程序可以使用Rust编译器来生成,这个编译器是:rustc.
$ rustc hello.rs
rustc可以生成一个可执行的二进制程序hello。
$ ./hello
Hello World!
1.1 注释
任何一个程序都需要注释并且Rust支持几种注释:常规注释会被编译器忽略:
// 行注释到行尾结束。
/* 块注释到分隔符结束。 */
文档注释被解析到HTML库文档:
/// 为其下面的项目产生库文档。
//! 为其下面的闭包项目产生文档。
fn main() { // This is an example of a line comment // Notice how there are two slashes at the beginning of the line // And that nothing written inside these will be read by the compiler // println!("Hello, world!"); // Run it. See? Now try deleting the two slashes, and run it again. /* * This is another type of comment, the block comment. In general, * the line comment is the recommended comment style however the * block comment is extremely useful for debugging */ /* Note, the previous column of `*` was entirely for style. There's no actual need for it. */ // Observe how block comments allow easy expression manipulation // which line comments do not. Deleting the comment deliminators // will change the result: let x = 5 + /* 90 + */ 5; println!("Is `x` 10 or 100? x = {}", x); }
程序输出的结果是:
Is `x` 10 or 100? x = 10
1.2 格式输出
打印通过定义在std::fmt中的一系列宏来处理,这些宏包括:format!:将格式化文本写入String
print! :与format! 类似,但是文本信息会打印到控制台
println! :与print! 一样,但是后添加一个换行。
所有的文本是以相同的方式解析的,唯一需要注意的是格式的正确性会在编译时检查。
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);
// You can right-align text with a specified width. This will output
// " 1". 5 white spaces and a "1".
println!("{number:>width$}", number=1, width=6);
// You can pad numbers with extra zeroes. This will output "000001".
println!("{number:>0width$}", number=1, width=6);
// It will even check to make sure the correct number of arguments are
// used.
println!("My name is {0}, {1} {0}", "Bond","James");
// 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.
}
程序输出结果为:
31 days
Alice, this is Bob. Bob, this is Alice
the quick brown fox jumps over the lazy dog
1 of 10 people know binary, the other half don't
1
000001
My name is Bond, James Bond
std::fmt 包含了许多主导显示方式的方法。下面是重要的两个:
fmt::Debug:使用{:?}标识。为了调试目的而存在的文本格式。
fmt::Display:使用{}标识。更优雅的用户友好的格式化文本。
这里使用fmt::Display是因为std标准库为这些类型提供了实现。要是来打印用户自定义的类型,则还有许多工作要做。
1.2.1 Debug
所有想使用std::fmt格式特定的类型需要对可打印进行实现。仅仅标准库类型提供了自动实现。所有其他的类型需要手动实现。fmt::Debug特性对这个实现非常直接。所有的类型能够derive(自动创建)fmt::Debug的实现。fmt::Display并不是这样的,需要手动实现。
// This structure cannot be printed either with `fmt::Display` or // with `fmt::Debug` struct UnPrintable(i32); // The `derive` attribute automatically creates the implementation // required to make this `struct` printable with `fmt::Debug`. #[derive(Debug)] struct DebugPrintable(i32);
所有的标准库类型使用{:?}都是自动可打印的:
// Derive the `fmt::Debug` implementation for `Structure`. `Structure`
// is a structure which contains a single `i32`.
#[derive(Debug)]
struct Structure(i32);
// Put a `Structure` inside of the structure `Deep`. Make it printable
// also.
#[derive(Debug)]
struct Deep(Structure);
fn main() {
// Printing with `{:?}` is similar to with `{}`.
println!("{:?} months in a year.", 12);
println!("{1:?} {0:?} is the {actor:?} name.",
"Slater",
"Christian",
actor="actor's");
// `Structure` is printable!
println!("Now {:?} will print!", Structure(3));
// The problem with `derive` is there is no control over how
// the results look. What if I want this to just show a `7`?
println!("Now {:?} will print!", Deep(Structure(7)));
}
打印结果:
12 months in a year.
"Christian" "Slater" is the "actor\'s" name.
Now Structure(3) will print!
Now Deep(Structure(7)) will print!
对上面用户自定义类型,fmt::Debug确实是可打印的,但是有失优雅。手动实现fmt::Display将能修正它。
1.2.2 Dispaly显示
fmt::Debug看起来并不简洁和整洁,所以定制化输出常常是有益的。可以通过手动实现使用{}作为打印标识的fmt::Display来完成,实现看起来是这样的:// Import (via `use`) the `fmt` module to make it available.
use std::fmt;
// Define a structure which `fmt::Display` will be implemented for. This is simply
// a tuple struct containing an `i32` bound to the name `Structure`.
struct Structure(i32);
// In order to use the `{}` marker, the trait `fmt::Display` must be implemented
// manually for the type.
impl fmt::Display for Structure {
// This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Write strictly the first element into the supplied output
// stream: `f`. Returns `fmt::Result` which indicates whether the
// operation succeeded or failed. Note that `write!` uses syntax which
// is very similar to `println!`.
write!(f, "{}", self.0)
}
}
fmt::Display或许比fmt::Debug整洁,但是这对于标准库来说会有一个问题。模糊类型会被怎样显示?例如,标准库为所有的Vec<T>提供了单一格式的实现,该是什么样的类型?或者都不是?
Vec<path>: /:/etc:/home/username:/bin (以:分割)
Vec<number>: 1,2,3 (以,分割)
因为对所有的类型来说没有理想的格式,标准库并不会假设一个。Rust并没有为Vec<T>或者其他的通用容器实现fmt::Display。这些通用的case必须使用fmt::Display。
尽管这样,这不是一个问题,因为对于任何一个新的容器,如果它不是通用则可以实现fmt::Display。
use std::fmt; // Import `fmt` // A structure holding two numbers. `Debug` will be derived so the results can // be contrasted with `Display`. #[derive(Debug)] struct MinMax(i64, i64); // Implement `Display` for `MinMax`. impl fmt::Display for MinMax { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Use `self.number` to refer to each positional data point. write!(f, "({}, {})", self.0, self.1) } } // Define a structure where the fields are nameable for comparison. #[derive(Debug)] struct Point2 { x: f64, y: f64, } // Similarly, implement for Point2 impl fmt::Display for Point2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Customize so only `x` and `y` are denoted. write!(f, "x: {}, y: {}", self.x, self.y) } } fn main() { let minmax = MinMax(0, 14); println!("Compare structures:"); println!("Display: {}", minmax); println!("Debug: {:?}", minmax); let big_range = MinMax(-300, 300); let small_range = MinMax(-3, 3); println!("The big range is {big} and the small is {small}", small = small_range, big = big_range); let point = Point2 { x: 3.3, y: 7.2 }; println!("Compare points:"); println!("Display: {}", point); println!("Debug: {:?}", point); // Error. Both `Debug` and `Display` were implemented but `{:b}` // requires `fmt::Binary` to be implemented. This will not work. // println!("What does Point2D look like in binary: {:b}?", point); }
程序执行结果为:
Compare structures:
Display: (0, 14)
Debug: MinMax(0, 14)
The big range is (-300, 300) and the small is (-3, 3)
Compare points:
Display: x: 3.3, y: 7.2
Debug: Point2 { x: 3.3, y: 7.2 }
我们实现了fmt::Display但是没有实现fmt::Binary,因此不能使用。std::fmt有许多这样的特性并且每一个都需要自己实现。详细信息可以在std::fmt中看到。
1.2.2.1 测试用例:List
为一个必须顺序处理的结构实现fmt::Display是棘手的。问题是每一个write!产生一个fmt::Result。适当的处理这个问题需要处理所有的结果。Rust提供了try!宏来实现这个目标。在write!上使用try!看起来是这样的:
// Try `write!` to see if it errors. If it errors, return // the error. Otherwise continue. try!(write!(f, "{}", value)); 使用try!实现一个Vec的fmt::Display是这样的: use std::fmt; // Import the `fmt` module. // Define a structure named `List` containing a `Vec`. struct List(Vec<i32>); impl fmt::Display for List { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Dereference `self` and create a reference to `vec` // via destructuring. let List(ref vec) = *self; try!(write!(f, "[")); // Iterate over `vec` in `v` while enumerating the iteration // count in `count`. for (count, v) in vec.iter().enumerate() { // For every element except the first, add a comma // before calling `write!`. Use `try!` to return on errors. if count != 0 { try!(write!(f, ", ")); } try!(write!(f, "{}", v)); } // Close the opened bracket and return a fmt::Result value write!(f, "]") } } fn main() { let v = List(vec![1, 2, 3]); println!("{}", v); }
程序输出为:
[1, 2, 3]
1.2.2 Dispaly显示
fmt::Debug看起来并不简洁和整洁,所以定制化输出常常是有益的。可以通过手动实现使用{}作为打印标识的fmt::Display来完成,实现看起来是这样的:// Import (via `use`) the `fmt` module to make it available.
use std::fmt;
// Define a structure which `fmt::Display` will be implemented for. This is simply
// a tuple struct containing an `i32` bound to the name `Structure`.
struct Structure(i32);
// In order to use the `{}` marker, the trait `fmt::Display` must be implemented
// manually for the type.
impl fmt::Display for Structure {
// This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Write strictly the first element into the supplied output
// stream: `f`. Returns `fmt::Result` which indicates whether the
// operation succeeded or failed. Note that `write!` uses syntax which
// is very similar to `println!`.
write!(f, "{}", self.0)
}
}
fmt::Display或许比fmt::Debug整洁,但是这对于标准库来说会有一个问题。模糊类型会被怎样显示?例如,标准库为所有的Vec<T>提供了单一格式的实现,该是什么样的类型?或者都不是?
Vec<path>: /:/etc:/home/username:/bin (以:分割)
Vec<number>: 1,2,3 (以,分割)
因为对所有的类型来说没有理想的格式,标准库并不会假设一个。Rust并没有为Vec<T>或者其他的通用容器实现fmt::Display。这些通用的case必须使用fmt::Display。
尽管这样,这不是一个问题,因为对于任何一个新的容器,如果它不是通用则可以实现fmt::Display。
use std::fmt; // Import `fmt` // A structure holding two numbers. `Debug` will be derived so the results can // be contrasted with `Display`. #[derive(Debug)] struct MinMax(i64, i64); // Implement `Display` for `MinMax`. impl fmt::Display for MinMax { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Use `self.number` to refer to each positional data point. write!(f, "({}, {})", self.0, self.1) } } // Define a structure where the fields are nameable for comparison. #[derive(Debug)] struct Point2 { x: f64, y: f64, } // Similarly, implement for Point2 impl fmt::Display for Point2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Customize so only `x` and `y` are denoted. write!(f, "x: {}, y: {}", self.x, self.y) } } fn main() { let minmax = MinMax(0, 14); println!("Compare structures:"); println!("Display: {}", minmax); println!("Debug: {:?}", minmax); let big_range = MinMax(-300, 300); let small_range = MinMax(-3, 3); println!("The big range is {big} and the small is {small}", small = small_range, big = big_range); let point = Point2 { x: 3.3, y: 7.2 }; println!("Compare points:"); println!("Display: {}", point); println!("Debug: {:?}", point); // Error. Both `Debug` and `Display` were implemented but `{:b}` // requires `fmt::Binary` to be implemented. This will not work. // println!("What does Point2D look like in binary: {:b}?", point); }
程序执行结果为:
Compare structures:
Display: (0, 14)
Debug: MinMax(0, 14)
The big range is (-300, 300) and the small is (-3, 3)
Compare points:
Display: x: 3.3, y: 7.2
Debug: Point2 { x: 3.3, y: 7.2 }
我们实现了fmt::Display但是没有实现fmt::Binary,因此不能使用。std::fmt有许多这样的特性并且每一个都需要自己实现。详细信息可以在std::fmt中看到。
1.2.3 格式
我们已经看到格式通过一个格式化字符串(format String)来指定:format!("{}", foo) -> "3735928559"
format!("0x{:X}", foo) -> "0xDEADBEEF"
format!("0o{:o}", foo) -> "0o33653337357"
同一个变量(foo)根据不同的参数类型能被格式化为不同的格式:X VS o VS unspecified(未指定类型)。
这种格式化功能通过特性实现,并且每种参数类型都有一个特性。最普通的格式化特性就是Display,它来出来那些未指定的参数类型:例如{}
use std::fmt::{self, Formatter, Display};
struct City {
name: &'static str,
// Latitude
lat: f32,
// Longitude
lon: f32,
}
impl Display for City {
// `f` is a buffer, this method must write the formatted string into it
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let lat_c = if self.lat >= 0.0 { 'N' } else { 'S' };
let lon_c = if self.lon >= 0.0 { 'E' } else { 'W' };
// `write!` is like `format!`, but it will write the formatted string
// into a buffer (the first argument)
write!(f, "{}: {:.3}°{} {:.3}°{}",
self.name, self.lat.abs(), lat_c, self.lon.abs(), lon_c)
}
}
fn main() {
for city in [
City { name: "Dublin", lat: 53.347778, lon: -6.259722 },
City { name: "Oslo", lat: 59.95, lon: 10.75 },
City { name: "Vancouver", lat: 49.25, lon: -123.1 },
].iter() {
println!("{}", *city);
}
}
程序输出结果:
Dublin: 53.348°N 6.260°W
Oslo: 59.950°N 10.750°E
Vancouver: 49.250°N 123.100°W
下面是所有的格式化特性和与之相对应的参数类型:
unspecified -> Display
? -> Debug
o -> Octal
x -> LowerHex
X -> UpperHex
p -> Pointer
b -> Binary
e -> LowerExp
E -> UpperExp
相关文章推荐
- SQLSERVER 中GO的作用详解
- 在Go语言程序中使用gojson来解析JSON格式文件
- 举例详解Go语言中os库的常用函数用法
- Go语言中函数的参数传递与调用的基本方法
- 深入解析Go语言的io.ioutil标准库使用
- GO语言的IO方法实例小结
- Go语言的os包中常用函数初步归纳
- Go语言中数组的基本用法演示
- GO语言类型转换和类型断言实例分析
- 深入解析Go语言编程中的递归使用
- 初步解读Golang中的接口相关编写方法
- Go语言实现的最简单数独解法
- 详解Golang编程中的常量与变量
- Go实现比较时间大小
- 深入剖析Go语言编程中switch语句的使用
- 简单讲解Go程序中使用MySQL的方法
- Go语言的Windows下环境配置以及简单的程序结构讲解
- 在Go程序中实现服务器重启的方法
- Go语言流程控制之goto语句与无限循环
- 在Mac OS上安装Go语言编译器的方法