我在这里有一个愚蠢的例子,只是为了演示我遇到的另一个库和模式匹配的问题 .
struct Person {
name: String,
age: i32,
choice: Choices
}
#[derive(Debug)]
enum Choices {
Good,
Neutral,
Evil
}
fn find(p: Person) {
match (p.choice, p.age) {
(Choices::Good, a) if a < 80 => {
announce(p);
}
(_, a) if a >= 80 => {
println!("You're too old to care.");
}
_ => {
println!("You're not very nice!")
}
}
}
fn announce(p: Person) {
println!("Your name is {}. You are {:?}.", p.name, p.choice);
}
fn main() {
let p = Person {
name: "Bob".to_string(),
age: 20,
choice: Choices::Good
};
find(p);
}
现在问题似乎是在模式匹配期间,移动语义将启动并获取我的Person中的内部结构(Thing)的所有权 .
当我把这个人移到下一个方法时,我不能因为它被部分移动了 .
Compiling match v0.1.0 (file:///home/jocull/Documents/Projects/Rust/learn/match)
src/main.rs:17:13: 17:14 error: use of partially moved value: `p`
src/main.rs:17 announce(p);
^
src/main.rs:15:9: 15:17 note: `p.choice` moved here because it has type `Choices`, which is non-copyable
src/main.rs:15 match (p.choice, p.age) {
^~~~~~~~
error: aborting due to previous error
Could not compile `match`.
我的直觉说我需要让Rust通过使用引用或某种借用来停止移动值 . 在这种情况下,我 could 将我的方法签名更改为借用,但对于某些库,您并不总是能够这样做 . (我想在这种情况下处理hyper ......)
有没有办法让 match
在匹配过程中使用引用而不是移动值?谢谢!
2 回答
为什么?
当你做元组时
你
memcpy
来自Person
p.choice
和p.age
.可以为
p.age
执行此操作,因为它是Copy
类型 - 您可以在memcpy
之后继续使用旧值 .p.choices
的类型为Choices
,这是 notCopy
. 这意味着memcpy
被视为"move",因此旧值不可用 . 这意味着p
处于无效状态,因此您无法在其上调用announce
.解决方案#1
由于
Choices
是一个微不足道的enum
,你可以只#[derive(Copy, Clone)]
. 这意味着您可以继续使用旧的p.choices
.如果你只能安全地制作
Choices
Clone
,那么你必须在match
中使用clone
.解决方案#2
你可以参考
p.choices
:这只能起作用,因为
&Choices::Good
是完全匹配,因此可以放弃借用 . 如果你有的话借用仍然是活动的,因此调用
announce(p)
时的移动将失败 - 移动将使活动的借用变量无效 .注意事项
你
announce
没有理由让announce
消耗Person
- 它只需要看一下它 . 只有在小型Copy
类型的情况下,才能获取参考值 .请注意,让
announce
获取引用意味着match
也可以保留p
中的引用,这使得它可以更广泛地应用 .to_string
主要用于非字符串对象 .into
和to_owned
更快,into
也更短 .所以我再次尝试新的代码更改:)
在您当前的代码中,如果您使用借用而不是移动匹配它是有效的 .
p.age
doesn 't need that only because it' s原始类型和基元类型实现Copy trait但Choices没有实现复制特性,因此它们会在匹配中移动 . 当你致电
announce()
时,这会导致他们无法使用它可以解决部分移动的错误 . 我想这是因为你在比赛中选择了 . 但选择是人的一部分,所以它部分移动 .
I have not enough knowledge of Rust to truly explain why it works, so if you can add something useful, please do