这个代码来自于rustlings的quiz2.rs。我知道for(string,command)中的命令是从向量迭代器中借来的。这个命令是借来的,但是为什么Append(n)中的'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
}
2条答案
按热度按时间kh212irz1#
首先,
Vec::iter()
返回一个对向量元素的 references 的迭代器,即&(String, Command)
。然后,每当你为某个特定的结构编写一个模式,比如
for
循环中的双元素元组(string, command)
,但输入是对该结构的 * 引用 *,Rust就会“通过”该引用进行匹配,并自动为你 * 提供对元素的引用 *(因为一般情况下不可能 * 不 * 获得引用,因为不是每个类型都是Copy
)。因此,
command
的类型是&Command
。然后match command {
也会发生同样的事情,并且match
的模式中的每个变量绑定(即n
)也将是一个引用。如果你想避免这种情况,你必须做的是 * 显式地写出与引用的匹配 *:
或者,您可以将输入解引用到
match
(只要您不绑定任何非Copy
值,这就不一定会尝试移出引用):最后,如果您希望 * 完全避免这种魔术 *,并编写一个显式执行整个过程的程序,您还需要调整
for
模式:ref
意味着“请不要试图将这个值 * 移出 * 我正在匹配的值;只是给予我一个参考。这在现代的Rust中很少见,因为我所说的自动匹配行为使得它几乎是不必要的。Rust的这个特性被称为“匹配人体工程学”,因为它让你不必一直写大量的&
和ref
。但是,正如你所看到的,它可以导致令人惊讶的行为,旧的显式样式还可以避免处理对Copy
类型(如整数)的不必要的引用。如果您想尝试在不使用匹配人体工程学的情况下编写Rust,以了解“实际发生了什么”,您可以启用Clippy restriction lint 来标记模式实际上不适合其匹配类型的任何位置:
并运行
cargo clippy
来查看新的警告。您可能会发现有相当多的模式隐式地作用于引用!vohkndzv2#
这是因为RFC 2005。在此之前,当你想在match中引用一个内部字段时,有一个特殊的语法
ref
和ref mut
。这里发生的是你的
command
是一个&Command
。你匹配它,但手臂都是Command
。所以command
被自动取消引用。但是,在Command::Append
中,你获得了内部n
的所有权。这是不可能发生的,因为你的command
是一个引用。所以rust给你一个对n
的引用。有多种方法可以解决这个问题,最简单的方法是自己解引用
n
,如下所示:当
n
是Copy
时,这是有效的。如果n
不是Copy
而是Clone
,您也可以在匹配体本身中执行let n = n.clone()
。您也可以取得
command
的拥有权,如下所示:如果你不能完成以上任何一项,那么你就需要处理引用本身,或者把你的迭代器从
input.iter()
改为input.into_iter()
,从一开始就得到一个拥有的Command
。