我在这里有一个愚蠢的例子,只是为了演示我遇到的另一个库和模式匹配的问题。
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通过使用引用或某种借用来停止移动值。在这种情况下,我可以将我的方法签名更改为借用,但对于某些库,您并不总是能够这样做。 (我想在这种情况下处理hyper ...)
有没有办法让match
在匹配过程中使用引用而不是移动值?谢谢!
答案 0 :(得分:12)
制作元组时
(p.choice, p.age)
您memcpy
中p.choice
和p.age
的{{1}}。
可以为Person
执行此操作,因为它是p.age
类型 - 您可以在Copy
之后继续使用旧值。
memcpy
类型为p.choices
,不 Choices
。这意味着Copy
被视为&#34;移动&#34;,因此旧值不可用。这意味着memcpy
处于无效状态,因此您无法在其上调用p
。
由于announce
是一个微不足道的Choices
,您只能enum
。这意味着您可以继续使用旧的#[derive(Copy, Clone)]
。
如果您只能安全地制作p.choices
Choices
,那么您必须Clone
代替clone
。
您可以通过引用:
获取match
p.choices
这只能起作用,因为match (&p.choice, p.age) {
(&Choices::Good, a) if a < 80 => {
announce(p);
}
...
}
是完全匹配的,因此可以放弃借用。如果你有了
&Choices::Good
借用仍然是活跃的,因此调用match (&p.choice, p.age) {
(&x, a) if a < 80 => {
announce(p);
}
...
}
时的移动将失败 - 移动将使活动的借用变量无效。
你在这里做了大量的事情 - 传递一些参考资料要灵活得多!没有理由announce(p)
消费 a announce
- 它只需要稍微查看一下。只有小Person
类型时,才建议您在参考时使用值。
请注意,让Copy
获取引用意味着announce
也可以保留match
内的引用,这使其更广泛适用。
p
主要用于非字符串对象。 <{1}}和to_string
速度更快,into
也更短。
to_owned
答案 1 :(得分:0)
所以我再次尝试新的代码更改:)
在您当前的代码中,如果您使用借用而不是移动匹配它是有效的。
p.age
并不仅仅因为它是原始类型而原始类型实现了Copy
trait
但Choices没有实现复制特性,所以他们在比赛中被移动了。当您拨打announce()
match (&p.choice, p.age) {
(&Choices::Good, a) if a < 80 => {
announce(p);
}
...
}
它可以解决有关部分移动的错误。我想这是因为你在比赛中选择了。但选择是人的一部分,所以它部分移动。
我对Rust没有足够的知识来真正解释它的工作原理,所以如果你能添加一些有用的东西,请