gpt4 book ai didi

rust - 可变引用有移动语义吗?

转载 作者:行者123 更新时间:2023-12-03 11:23:43 24 4
gpt4 key购买 nike

fn main() {
let mut name = String::from("Charlie");
let x = &mut name;
let y = x; // x has been moved
say_hello(y);
say_hello(y); // but y has not been moved, it is still usable
change_string(y);
change_string(y);

}

fn say_hello(s: &str) {
println!("Hello {}", s);
}

fn change_string(s: &mut String) {
s.push_str(" Brown");
}
当我分配 xy x已被移动。但是,当我在函数中使用它时,我希望可以移动具有移动语义的东西。但是,我仍然可以在后续调用后使用引用。也许这与 say_hello() 接受不可变引用有关,但 change_string() 接受可变引用但引用仍未移动。

最佳答案

你的推理和观察都是完全正确的。看起来事情应该按照你描述的方式发生。然而,编译器在这里应用了一些便利魔法。
移动语义在 Rust 中通常适用于所有未实现 Copy 的类型。特征。共享引用是 Copy ,因此它们在分配或传递给函数时会被简单地复制。可变引用不是 Copy ,所以他们应该被移动。
这就是魔法开始的地方。每当将可变引用分配给编译器已知为可变引用的类型的名称时,原始引用将被隐式重新借用,而不是被移动。所以函数调用

change_string(y);
被编译器转换为意思
change_string(&mut *y);
原始引用被取消引用,并创建一个新的可变借用。这个新借位被移到函数中,一旦函数返回,原始借位就会被释放。
请注意,这不是函数调用和赋值之间的区别。每当编译器已知目标类型是可变引用时,就会发生隐式重新借用,例如因为模式有一个明确的类型注释。所以这一行也创建了一个隐式的重新借用,因为我们显式地将它注释为一个可变引用类型:
let y: &mut _ = x;
另一方面,此函数调用移动(并因此消耗)可变引用 y :
fn foo<T>(_: T) {}

[...]
foo(y);
泛型 T这里不是明确的可变引用类型,因此不会发生隐式重新借用,即使编译器推断该类型是可变引用 - 就像您的赋值 let y = x; 的情况一样.
在某些情况下,即使没有显式类型注释,编译器也可以推断泛型类型是可变引用:
fn bar<T>(_a: T, _b: T) {}

fn main() {
let mut i = 42;
let mut j = 43;
let x = &mut i;
let y = &mut j;
bar(x, y); // Moves x, but reborrows y.
let _z = x; // error[E0382]: use of moved value: `x`
let _t = y; // Works fine.
}
在推断第一个参数的类型时,编译器还不知道它是一个可变引用,因此不会发生隐式重新借用和 x被移动到函数中。但是,当到达第二个参数时,编译器已经推断出 T是可变引用,所以 y被隐式地重新借用。 (这个例子很好地说明了为什么添加编译器魔法来使事情“正常工作”通常是一个坏主意。显式比隐式好。)
不幸的是, this behaviour currently isn't documented in the Rust reference .
也可以看看:
  • Stuff the Identity Function Does (in Rust)
  • Discussion of the topic on the Rust users forum
  • Why is the mutable reference not moved here?
  • 关于rust - 可变引用有移动语义吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62960584/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com