我注意到了Microsoft的Rust初学者指南中的代码:
fn count_letters(text: &str) -> usize {
text.chars().filter(|ref c| c.is_alphabetic()).count()
}
显然,在没有 ref 的情况下,代码仍然可以正常工作。
那么这里为什么使用了 ref?我应该在什么时候使用 ref?这里是否有任何惯用的编程实践?
我注意到了Microsoft的Rust初学者指南中的代码:
fn count_letters(text: &str) -> usize {
text.chars().filter(|ref c| c.is_alphabetic()).count()
}
显然,在没有 ref 的情况下,代码仍然可以正常工作。
那么这里为什么使用了 ref?我应该在什么时候使用 ref?这里是否有任何惯用的编程实践?
引用自Rust Book:
In older versions of Rust,
matchwould assume that you want to move what is matched. But sometimes, that’s not what you wanted. For example:let robot_name = &Some(String::from("Bors")); match robot_name { Some(name) => println!("Found a name: {}", name), None => (), } println!("robot_name is: {:?}", robot_name);Here,
robot_nameis a&Option<String>. Rust would then complain thatSome(name)doesn’t match up with&Option<T>, so you’d have to write this:let robot_name = &Some(String::from("Bors")); match robot_name { &Some(name) => println!("Found a name: {}", name), None => (), } println!("robot_name is: {:?}", robot_name);Next, Rust would complain that name is trying to move the
Stringout of the option, but because it’s a reference to an option, it’s borrowed, and so can’t be moved out of. This is where therefkeyword comes into play:let robot_name = &Some(String::from("Bors")); match robot_name { &Some(ref name) => println!("Found a name: {}", name), None => (), } println!("robot_name is: {:?}", robot_name);The
refkeyword is like the opposite of&in patterns; this says “please bindname* to be a&String, don’t try to move it out." In other words, the&in&Someis matching against a reference, but ref creates a reference.ref mutis likeref, but for mutable references.Anyway, today’s Rust doesn’t work like this. If you try to match on something borrowed, then all of the bindings you create will attempt to borrow as well. This means that the original code works as you’d expect.
Because Rust is backwards compatible, we couldn’t remove ref and
ref mut, and they’re sometimes useful in obscure situations, where you want to partially borrow part of astructas mutable and another part as immutable. But you may see them in older Rust code, so knowing what they do is still useful.
*这是一项小更正,书中应该使用 ref 而非 name
ref创建与匹配内容相应的引用,而&则与引用进行比较。 - onlycparra& 匹配一个引用,但当它绑定到一个标识符时,该值也会被 _解引用_。这就是为什么上面的中间示例会导致移动的原因。 - Peter Hall
ref是必要的。今天,你很可能永远不会遇到必须使用它的情况。它是一个遗留物。 - Denys Séguretref现在被认为是遗留的了!我理解替代方法就是一开始就使用借用,例如if let Some(inner) = &option而不是if let Some(ref inner) = option。我怀疑在问题中引用ref在 Rust 1.0 版本之后从未必要,因为char是可复制的,并且你总是可以调用拥有值的方法。 - user4815162342.filter(|&c| ...)(当使用需要手动比较c的闭包调用filter时,这种写法经常出现),而不小心写成了ref。 - user4815162342ref仍然是必要的。我不同意书中将其称为“遗留代码”的说法。(我也不喜欢 match ergonomics 引入的复杂性和混乱,但这是另一回事。) - Sven Marnach