@@ -18,32 +18,53 @@ fn gcd(mut n: u64, mut m: u64) -> u64 {
18
18
fn test_gcd ( ) {
19
19
assert_eq ! ( gcd( 14 , 15 ) , 1 ) ;
20
20
21
- assert_eq ! ( gcd( 2 * 3 * 5 * 11 * 17 ,
22
- 3 * 7 * 11 * 13 * 19 ) ,
23
- 3 * 11 ) ;
21
+ assert_eq ! ( gcd( 2 * 3 * 5 * 11 * 17 , 3 * 7 * 11 * 13 * 19 ) , 3 * 11 ) ;
24
22
}
25
23
26
- use std:: str:: FromStr ;
24
+ /* 将标准库中的 FromStr特型引入了当前作用域。特型是可以由类型实现的方法集合。任何实现了 FromStr 特型的类型都有一个 from_str 方法,
25
+ 该方法会尝试从字符串中解析这个类型的值。u64 类型实现了 FromStr,所以我们将调用 u64::from_str 来解析程序中的命令行参数。
26
+ 尽管我们从未在程序的其他地方用到 FromStr 这个名字,但仍然要 use(使用)它,因为要想使用某个特型的方法,该特型就必须在作用域内。
27
+ */
27
28
use std:: env;
29
+ /* 第二个 use 声明引入了 std::env 模块,该模块提供了与执行环境交互时会用到的几个函数和类型,包括 args 函数,该函数能让我们访问程序中的命令行参数。 */
30
+ use std:: str:: FromStr ;
28
31
29
32
fn main ( ) {
33
+ //main 函数没有返回值,所以可以简单地省略 -> 和通常会跟在参数表后面的返回类型。
34
+ /* numbers 的类型是 Vec<u64>,这是一个可以容纳 u64 类型的值的向量,但和以前一样,不需要把类型写出来。Rust 会推断它,
35
+ 一部分原因是我们将 u64 类型的值压入了此向量,另一部分原因是我们将此向量的元素传给了 gcd,后者只接受 u64 类型的值。 */
30
36
let mut numbers = Vec :: new ( ) ;
31
-
37
+ /* 这里使用了 for 循环来处理命令行参数,依次将变量 arg 指向每个参数并运行循环体。std::env 模块的 args 函数会返回一个迭代器,
38
+ 此迭代器会按需生成1每个参数,并在完成时给出提示。 */
32
39
for arg in env:: args ( ) . skip ( 1 ) {
33
- numbers. push ( u64:: from_str ( & arg)
34
- . expect ( "error parsing argument" ) ) ;
40
+ /* args 返回的迭代器生成的第一个值永远是正在运行的程序的名称。如果想跳过它,
41
+ 就要调用迭代器的 skip方法来生成一个新的迭代器,新迭代器会略去第一个值。 */
42
+
43
+ /* 这里我们调用了 u64::from_str 来试图将命令行参数 arg 解析为一个无符号的 64 位整数。u64::from_str 并不是 u64 值上的某个方法,
44
+ 而是与 u64 类型相关联的函数,类似于 C++或 Java 中的静态方法。from_str 函数不会直接返回 u64,
45
+ 而是返回一个指明本次解析已成功或失败的 Result 值。Result值是以下两种变体之一:形如 Ok(v) 的值,
46
+ 表示解析成功了,v 是所生成的值;形如 Err(e) 的值,表示解析失败了,e 是解释原因的错误值。执行任何可能会失败的操作(例如执行输入或输出
47
+ 或者以其他方式与操作系统交互)的函数都会返回一个 Result 类型,其Ok 变体会携带成功结果(传输的字节数、打开的文件等),
48
+ 而其 Err 变体会携带错误码,以指明出了什么问题。与大多数现代语言不同,Rust 没有异常(exception):所有错误都使用 Result 或 panic 进行处理,
49
+
50
+ 我们用 Result 的 expect 方法来检查本次解析是否成功。如果结果是 Err(e),那么 expect 就会打印出一条包含 e 的消息并直接退出程序。
51
+ 但如果结果是 Ok(v),则 expect 会简单地返回 v 本身,最终我们会将其压入这个数值向量的末尾。 */
52
+ numbers. push ( u64:: from_str ( & arg) . expect ( "error parsing argument" ) ) ;
35
53
}
36
54
55
+ /* 空数组没有最大公约数,因此要检查此向量是否至少包含一个元素,如果没有则退出程序并报错。这里我们用 eprintln! 宏将错误消息写入标准错误流。 */
37
56
if numbers. len ( ) == 0 {
38
57
eprintln ! ( "Usage: gcd NUMBER ..." ) ;
39
58
std:: process:: exit ( 1 ) ;
40
59
}
41
60
42
61
let mut d = numbers[ 0 ] ;
62
+ // 所以在进行迭代时,需要告诉 Rust,该向量的所有权应该留在 numbers 上,我们只是为了本次循环而借用它的元素。&numbers[1..] 中的 & 运算符会从向量中借用从第二个元素开始的引用
63
+ /* for 循环会遍历这些被引用的元素,让 m 依次借出每个元素。*m 中的 * 运算符会将 m解引用,产生它所引用的值,这就是要传给 gcd 的下一个 u64。
64
+ 最后,由于numbers 拥有着此向量,因此当 main 末尾的 numbers 超出作用域时,Rust 会自动释放它。 */
43
65
for m in & numbers[ 1 ..] {
44
66
d = gcd ( d, * m) ;
45
67
}
46
68
47
- println ! ( "The greatest common divisor of {:?} is {}" ,
48
- numbers, d) ;
69
+ println ! ( "The greatest common divisor of {:?} is {}" , numbers, d) ;
49
70
}
0 commit comments