所有权转移后改变变量
Mutating variable after ownership transfer
我知道如何使代码工作我只是想知道为什么会这样。
假设有以下程序:
fn dummy(name: String) {
let last_name = " Wang".to_string();
name.push_str(&last_name);
println!("Hello, {}", name);
}
fn main() {
println!("What is your name?");
let mut name = String::new();
std::io::stdin().read_line(&mut name).expect("Couldn't read input!");
name.pop();
dummy(name);
}
尝试编译时出现以下错误:
error[E0596]: cannot borrow `name` as mutable, as it is not declared as mutable
--> print.rs:3:5
|
1 | fn dummy(name: String) {
| ---- help: consider changing this to be mutable: `mut name`
2 | let last_name = " Wang".to_string();
3 | name.push_str(&last_name);
| ^^^^ cannot borrow as mutable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0596`.
我知道只需在函数定义中的 name
旁边添加 mut
就可以解决这个问题,但是当变量 name
被定义为时,为什么需要在函数定义中将其声明为可变的先前在 main
函数内部可变?
编译器不应该知道变量之前是可变的,为什么它不能转移所有权和可变的“属性”?
也许这是个愚蠢的问题,但我是 Rust 的新手。如果它表现得如此,它会引入一些新的 problems/bugs 的可能性吗?如果有,能举几个例子吗?
name
作为参数传递的事实只是一个细节。
在这个简化的示例中,我们可以重现相同的效果。
fn main() {
let mut name1 = "first".to_owned();
name1.push_str(" second");
let mut name2 = name1;
name2.push_str(" third");
let name3 = name2;
// name3.push_str(" fourth"); // rejected
let mut name4 = name3;
name4.push_str(" fifth");
println!("{}", name4);
}
字符串的所有权从 name1
更改为 name2
,name3
然后 name4
并且每个变量(绑定)决定(有或没有 mut
) 如果它现在是唯一所有者的字符串可以被改变。
初始化函数的参数类似于初始化另一个变量 (borrowing/ownership-transfer/copy...),一旦进入函数内部,参数就被视为任何其他局部变量,在这种情况下可能是可变的,也可能不是.
如果你打算修改这个参数,你可以用 mut
声明它,或者将它传递给另一个用 mut
.
声明的局部变量。
请注意,我们在这里处理的是 值,而不是引用。
当然,您不能从 &T
初始化 &mut T
。
但是在引用前添加 mut
(如 mut &T
或 mut &mut T
)提供了将此引用重新分配给另一个值的能力(是否可变,取决于正确的 mut
).
如果您熟悉 C 或 C++,这类似于在声明指针时在星号前后(或两边)使用 const
。
简而言之,在变量上使用 mut
是相对于 你的意图 在你的算法中修改存储在这个变量中的内容,但它不是 属性 这个变量的内容。
除了@prog-fh 的回答之外,Rust 的一个重要特性是它允许 local 推理。换句话说,当您查看定义时,您应该拥有确定代码是否正确以及它可以做什么或不能做什么所需的所有信息。在您的情况下,这意味着 dummy
将如何调用以及将传递哪些参数并不重要,它的定义必须能够独立存在。所以你应该能够通过查看这部分代码来了解所有关于它的知识:
fn dummy(name: String) {
let last_name = " Wang".to_string();
name.push_str(&last_name);
println!("Hello, {}", name);
}
这使得在使用其他人编写的函数时更容易以团队形式编写代码,或者当您可能不记得最初编写函数时的所有细节时,可以更轻松地维护代码 运行一段代码。
我知道如何使代码工作我只是想知道为什么会这样。
假设有以下程序:
fn dummy(name: String) {
let last_name = " Wang".to_string();
name.push_str(&last_name);
println!("Hello, {}", name);
}
fn main() {
println!("What is your name?");
let mut name = String::new();
std::io::stdin().read_line(&mut name).expect("Couldn't read input!");
name.pop();
dummy(name);
}
尝试编译时出现以下错误:
error[E0596]: cannot borrow `name` as mutable, as it is not declared as mutable
--> print.rs:3:5
|
1 | fn dummy(name: String) {
| ---- help: consider changing this to be mutable: `mut name`
2 | let last_name = " Wang".to_string();
3 | name.push_str(&last_name);
| ^^^^ cannot borrow as mutable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0596`.
我知道只需在函数定义中的 name
旁边添加 mut
就可以解决这个问题,但是当变量 name
被定义为时,为什么需要在函数定义中将其声明为可变的先前在 main
函数内部可变?
编译器不应该知道变量之前是可变的,为什么它不能转移所有权和可变的“属性”?
也许这是个愚蠢的问题,但我是 Rust 的新手。如果它表现得如此,它会引入一些新的 problems/bugs 的可能性吗?如果有,能举几个例子吗?
name
作为参数传递的事实只是一个细节。
在这个简化的示例中,我们可以重现相同的效果。
fn main() {
let mut name1 = "first".to_owned();
name1.push_str(" second");
let mut name2 = name1;
name2.push_str(" third");
let name3 = name2;
// name3.push_str(" fourth"); // rejected
let mut name4 = name3;
name4.push_str(" fifth");
println!("{}", name4);
}
字符串的所有权从 name1
更改为 name2
,name3
然后 name4
并且每个变量(绑定)决定(有或没有 mut
) 如果它现在是唯一所有者的字符串可以被改变。
初始化函数的参数类似于初始化另一个变量 (borrowing/ownership-transfer/copy...),一旦进入函数内部,参数就被视为任何其他局部变量,在这种情况下可能是可变的,也可能不是.
如果你打算修改这个参数,你可以用 mut
声明它,或者将它传递给另一个用 mut
.
请注意,我们在这里处理的是 值,而不是引用。
当然,您不能从 &T
初始化 &mut T
。
但是在引用前添加 mut
(如 mut &T
或 mut &mut T
)提供了将此引用重新分配给另一个值的能力(是否可变,取决于正确的 mut
).
如果您熟悉 C 或 C++,这类似于在声明指针时在星号前后(或两边)使用 const
。
简而言之,在变量上使用 mut
是相对于 你的意图 在你的算法中修改存储在这个变量中的内容,但它不是 属性 这个变量的内容。
除了@prog-fh 的回答之外,Rust 的一个重要特性是它允许 local 推理。换句话说,当您查看定义时,您应该拥有确定代码是否正确以及它可以做什么或不能做什么所需的所有信息。在您的情况下,这意味着 dummy
将如何调用以及将传递哪些参数并不重要,它的定义必须能够独立存在。所以你应该能够通过查看这部分代码来了解所有关于它的知识:
fn dummy(name: String) {
let last_name = " Wang".to_string();
name.push_str(&last_name);
println!("Hello, {}", name);
}
这使得在使用其他人编写的函数时更容易以团队形式编写代码,或者当您可能不记得最初编写函数时的所有细节时,可以更轻松地维护代码 运行一段代码。