火柴为什么在铁锈中被借用

  • 本文关键字:火柴 rust
  • 更新时间 :
  • 英文 :


代码用例来自rustlings'quiz2.rs'。我知道'for(string,command('中的命令是从矢量迭代器中借来的。命令是借用的,但为什么还借用了"n"Append(n(?

pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
// TODO: Complete the output declaration!
let mut output: Vec<String> = vec![];
for (string, command) in input.iter() {
// TODO: Complete the function body. You can do it!
match command {
Command::Uppercase => output.push(string.to_uppercase()),
Command::Trim => output.push(string.trim().to_string()),
Command::Append(n) => {
let can_mv_str = string.to_string() + &"bar".repeat(*n);
output.push(can_mv_str);
}
}
}
output
}

首先,Vec::iter()引用上返回一个迭代器到向量的元素,即&(String, Command)

然后,每当您为某个特定结构编写模式时,比如for循环中的2元素元组(string, command),但输入是该结构的引用,Rust就会匹配";通过";引用,并自动为元素提供引用(因为通常不可能获取引用,因为不是每个类型都是Copy(。

因此,command的类型是&Command。然后同样的事情发生在match command {上,match模式中的每个变量绑定(即n(也将是一个引用。

如果你想避免这种情况,你必须做的是显式地写出与引用匹配的

match command {
...
&Command::Append(n) => {
let can_mv_str = string.to_string() + &"bar".repeat(n);
output.push(can_mv_str);
}
}

或者,您可以将输入取消引用到match(这不一定会试图移出引用——只要您不绑定任何非Copy值(:

match *command {
...
Command::Append(n) => {
let can_mv_str = string.to_string() + &"bar".repeat(n);
output.push(can_mv_str);
}
}

最后,如果您想完全避免魔术并编写一个明确完成整个任务的程序,您还需要调整for模式:

for &(ref string, ref command) in input.iter() {

CCD_ 14表示";请不要试图这个值从我匹配的值中移出;请给我一个参考。它在现代Rust中很少出现,因为我所说的自动匹配行为使它基本上没有必要。Rust的这一功能被称为"匹配人体工程学",因为它可以让你不用一直写很多&ref。但是,正如您所看到的,它可能会导致令人惊讶的行为,而且旧的显式样式还可以避免处理对Copy类型(如整数(的不必要引用。

如果你想尝试在不使用匹配人体工程学的情况下编写Rust,以了解"到底发生了什么",你可以启用Clippy限制lint来标记任何图案实际上不适合匹配类型的地方:

#[warn(clippy::pattern_type_mismatch)]

并运行CCD_ 18以查看新的警告。您可能会发现,有相当多的模式在隐式地处理引用!

这是因为RFC 2005。在此之前,当您想要引用match中的内部字段时,曾经有refref mut的特殊语法。

这里发生的情况是,您的command&Command。你在上面匹配,但手臂都是Command。因此command会自动取消引用。但是,在Command::Append中,您获得了内部n的所有权。这不可能发生,因为您的command是一个参考。因此,rust为您提供了n的参考。

您可以通过多种方式解决此问题。最简单的方法是自己取消引用n,如下所示:

match command {
Command::Append(&n) => ..., // n is owned here
...
}

nCopy时,此操作有效。如果n不是Copy而是Clone,您也可以在匹配主体本身中执行let n = n.clone()

您也可以拥有command,如下所示:

match *command { // if Command is Copy
Command::Append(n) => ..., // n is owned here
...
}
// OR
match command.clone() { // if Command is Clone
Command::Append(n) => ..., // n is owned here
...
}

如果您不能执行以上任何操作,那么您将需要使用引用本身,或者可能将迭代器从input.iter()更改为input.into_iter(),以从一开始就获得一个拥有的Command

最新更新