为什么这个 Rust 程序忽略了不可变性

7
我有以下 Rust 程序,我希望它会因为后面重新赋值了变量 x 而导致编译错误。但实际上程序能够编译并输出结果。这是为什么呢?
fn main() {
   let (x, y) = (1, 3);
   println!("X is {} and Y is {}", x, y);

   let x: i32 = 565;
   println!("Now X is {}", x);
}
1个回答

13

Rust实际上允许您在一个块中遮蔽其他变量,因此let x: i32 = 565;定义了一个新的变量x,它遮蔽了之前用let (x,y) = (1,3);定义的x。请注意,您甚至可以重新定义x以具有不同的类型,因为第二个x是一个全新的变量!

fn main(){
   let x = 1;
   println!("Now X is {}",x);

   let x = "hi";
   println!("Now X is {}",x);
}

这个reddit帖子更详细地解释了为什么这很有用。提到的两件有趣的事情是:

  • For operations which take ownership of the variable, but return another variable of the same type, it sometimes "looks nice" to redefine the returned variable to have the same name. From here:

    let iter = vec.into_iter();
    let iter = modify(iter);
    let iter = double(iter);
    
  • Or to make a variable immutable:

    let mut x;
    // Code where `x` is mutable
    let x = x;
    // Code where `x` is immutable
    

1
为什么语言允许这样做?这不会在大型程序中导致难以解决的逻辑错误吗?阴影化的目的是什么,还有其他使用这些概念的语言吗? - Viraj
你如何引用先前被遮蔽的变量? - Dai
3
@Dai 我认为你不能... 你可以将所有权转移到另一个变量中,例如 let y = x - Alec
4
“允许这样做是因为它被发现很有用。大多数编程语言都允许阴影变量,虽然 Rust 在同一代码块内允许阴影变量可能是独特的。至于逻辑错误...两面都能摇摆。有时候能够保证参数/变量之后不会被访问也是非常有用的。但说实话我更喜欢不使用它。” - Matthieu M.
8
我使用模仿技术来处理中间类型,将其转换为其他类型,并知道我不会再需要它。例如,一个函数有一个参数foo: Option<u32>,我会立即使用let foo = foo.unwrap_or(0) 来解包它。这样可以避免我需要为此变量想出一个新的名称,也可以防止未来的维护者需要思考要使用哪个外观类似的变量。 - Peter Hall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接