我正在学习Rust,我遇到了这个:
let mut x: i32 = 1;
x = 7;
let x = x; // x is now immutable and is bound to 7
let y = 4;
let y = "I can also be bound to text!"; // y is now of a different type
这怎么可能安全?请查看以下内容:
let temp = 23;
// 200 lines of code
// I'm changing something here <====== IMPORTANT
let temp = 101;
// 200 lines of code
// do something with temp (with 23 not 101 !!!)
如果我再次let temp = 101
,我无法知道我刚刚在代码中创建了一个令人讨厌的错误。在输入let temp
之前,我是否真的需要搜索let temp
?我错过了什么?
答案 0 :(得分:7)
问题不是Rust,或者任何编程语言,它都是代码。特别是这个&#34;行&#34;:
// 200 lines of code
如果你在变量声明和使用它之间编写200(或400!)行代码,很可能会发生意外情况。但是,如果变量是可变的并且您意外地更改了它,那么也可能发生这种情况:
let mut a = 1;
a += 1;
// or
let a = 1;
let a = 2;
两者都有相同的最终结果,但其中只有一个涉及阴影。
就个人而言,我发现使用Rust的包装类型(如Option
或Result
)时,阴影非常有用:
fn foo(name: Option<&str>) {
let name = name.unwrap_or("Who are you");
println!("{}", name);
}
如果您发现自己无法处理变量阴影,那么我建议您查看Clippy,其中有多个shadow_*
lint,您可以打开并禁止您的代码来自编译,如果你有任何阴影。
有时候你正在改变别人的代码。我无法知道
a
已被使用。我如何选择一个变量名呢?
我建议您在修改代码之前阅读代码。有些编辑还允许在文本中搜索模式或突出显示模式。
我来自Java,那是完全倒退的!这意味着,一旦您在范围内声明
int x
,您就无法重新声明它。
这是真的,但您仍然可以隐藏您的实例或类变量:
public class HelloWorld {
static int a = 42;
public static void main(String[] args) {
int a = 21;
System.out.print(a); // Oh no, it's not 42 anymore!
}
}
Java编译器不能防止这个错误;它取决于您,您的测试,代码审查或外部linting工具。
如何避免在Rust中的代码块内意外重新声明变量?
你桌子旁边可能有一张小纸条。在上面写上数字零。每次声明一个新变量时,都会在数字中添加一个变量。使用该数字为所有变量添加前缀或后缀。
为了安全起见,您还可以将您的名字添加到变量中 - 您不希望与遵循相同算法的任何其他人发生冲突。您可能还希望将函数和类型添加到变量的名称中,以避免不同函数之间的冲突。
当然,这些变量名称可能很长。要解决这个问题,您可能希望缩写上述所有内容,并将数字写为十六进制或Base64。您可以使用相当独特的my_type_cool_function_john_doe_x_12223123
,而不是mtcfjdxBA8293
。这不太可能与任何现有变量发生冲突。
(以上是讽刺)
毫无疑问:我强烈认为问题是不变量阴影:它的数百行长的函数需要如此多的精神开销。在这些类型上创建函数,创建类型和方法,但以某种方式修复代码,然后再将其进一步更改。
答案 1 :(得分:3)
任何具有覆盖100行代码的生命周期的变量都应该具有长且具有描述性的名称,并且通常不应该被遮挡。
temp
和x
之类的名称只能用于短生命周期的变量 - 十几行或更少 - 以便对变量的任何使用,你可以在几行之前轻松看到它的定义。
答案 2 :(得分:3)
另一点,只是针对Java比较以及正在使用的“删除”或“覆盖”散文,例如:
每次让x = 3时吓人都没有意义;因为你可能正在删除先前声明的值。
Rust仍然有范围规则。阴影尊重范围。与Java不同,您可以隐藏变量,但它会保留原始范围。 For example:
fn main() {
let x = 3;
{
let x = 5;
println!("Inner scope: {}", x); // Prints 5
}
println!("Outer scope: {}", x); // Prints 3
}
阴影考虑了范围。
答案 3 :(得分:2)
如果你有一个长达数百行的方法并且想要引入一个新变量,我建议你不要在long方法中添加更多变量,而是在你想要的地方调用一个函数。引入一个新变量。然后,您将获得两个优势:一个新的范围,您知道您的变量不是阴影或阴影,而且您不会在已经很长的方法中添加代码。