可变性
当你用let
声明一个变量时,它是不可改变的(不能改变)。
这将无法工作:
fn main() { let my_number = 8; my_number = 10; // ⚠️ }
编译器说:error[E0384]: cannot assign twice to immutable variable my_number
。这是因为如果你只写let
,变量是不可变的。
但有时你想改变你的变量。要创建一个可以改变的变量,就在let
后面加上mut
。
fn main() { let mut my_number = 8; my_number = 10; }
现在没有问题了。
但是,你不能改变类型:甚至mut
也不能让你这样做:这将无法工作。
fn main() { let mut my_variable = 8; // it is now an i32. That can't be changed my_variable = "Hello, world!"; // ⚠️ }
你会看到编译器发出的同样的 "预期"信息。expected integer, found &str
. &str
是一个字符串类型,我们很快就会知道。
遮蔽
shadowing是指使用let
声明一个与另一个变量同名的新变量。它看起来像可变性,但完全不同。shadowing看起来是这样的:
fn main() { let my_number = 8; // This is an i32 println!("{}", my_number); // prints 8 let my_number = 9.2; // This is an f64 with the same name. But it's not the first my_number - it is completely different! println!("{}", my_number) // Prints 9.2 }
这里我们说我们用一个新的 "let绑定"对my_number
进行了 "shadowing"。
那么第一个my_number
是否被销毁了呢?没有,但是当我们调用my_number
时,我们现在得到my_number
的f64
。因为它们在同一个作用域块中(同一个 {}
),我们不能再看到第一个 my_number
。
但如果它们在不同的块中,我们可以同时看到两个。 例如:
fn main() { let my_number = 8; // This is an i32 println!("{}", my_number); // prints 8 { let my_number = 9.2; // This is an f64. It is not my_number - it is completely different! println!("{}", my_number) // Prints 9.2 // But the shadowed my_number only lives until here. // The first my_number is still alive! } println!("{}", my_number); // prints 8 }
因此,当你对一个变量进行shadowing处理时,你不会破坏它。你屏蔽了它。
那么shadowing的好处是什么呢?当你需要经常改变一个变量的时候,shadowing是很好的。想象一下,你想用一个变量做很多简单的数学运算。
fn times_two(number: i32) -> i32 { number * 2 } fn main() { let final_number = { let y = 10; let x = 9; // x starts at 9 let x = times_two(x); // shadow with new x: 18 let x = x + y; // shadow with new x: 28 x // return x: final_number is now the value of x }; println!("The number is now: {}", final_number) }
如果没有shadowing,你将不得不考虑不同的名称,尽管你并不关心x。
fn times_two(number: i32) -> i32 { number * 2 } fn main() { // Pretending we are using Rust without shadowing let final_number = { let y = 10; let x = 9; // x starts at 9 let x_twice = times_two(x); // second name for x let x_twice_and_y = x_twice + y; // third name for x! x_twice_and_y // too bad we didn't have shadowing - we could have just used x }; println!("The number is now: {}", final_number) }
一般来说,你在Rust中看到的shadowing就是这种情况。它发生在你想快速取用变量,对它做一些事情,然后再做其他事情的地方。而你通常将它用于那些你不太关心的快速变量。