我可以在enum
上使用具有一个String
参数的模式匹配:
extern crate robots;
use std::any::Any;
use robots::actors::{Actor, ActorCell};
#[derive(Clone, PartialEq)]
pub enum ExampleMessage {
Msg { param_a: String },
}
pub struct Dummy {}
impl Actor for Dummy {
// Using `Any` is required for actors in RobotS
fn receive(&self, message: Box<Any>, _context: ActorCell) {
if let Ok(message) = Box::<Any>::downcast::<ExampleMessage>(message) {
match *message {
ExampleMessage::Msg { param_a } => println!("got message"),
}
}
}
}
然而我无法在带有2个参数的枚举上执行模式匹配:
#[derive(Clone, PartialEq)]
pub enum ExampleMessage {
Msg { param_a: String, param_b: usize },
}
impl Actor for Dummy {
// Using `Any` is required for actors in RobotS
fn receive(&self, message: Box<Any>, _context: ActorCell) {
if let Ok(message) = Box::<Any>::downcast::<ExampleMessage>(message) {
match *message {
ExampleMessage::Msg { param_a, param_b } => println!("got message"),
}
}
}
}
这会导致错误:
error[E0382]: use of moved value: `message`
--> src/example.rs:19:48
|
19 | ExampleMessage::Msg { param_a, param_b } => {
| ------- ^^^^^^^ value used here after move
| |
| value moved here
|
= note: move occurs because `message.param_a` has type `std::string::String`, which does not implement the `Copy` trait
我之前在同一enum
尝试了模式匹配而没有向下转换,这很好但我需要向下转发。
这对我来说似乎很奇怪,我不知道如何规避这个错误。
我正在使用Rust 1.19.0-nightly(afa1240e5 2017-04-29)
答案 0 :(得分:4)
我尝试在同一个枚举上进行模式匹配而不进行向下转换,这样可以正常工作
这是减少问题的一个很好的尝试。问题是你减少了太多。将Box<T>
向下转换为Foo
并不会返回Foo
,it returns a Box<Foo>
:
fn downcast<T>(self) -> Result<Box<T>, Box<Any + 'static>>
您可以使用以下方法重现问题:
#[derive(Clone, PartialEq)]
pub enum ExampleMessage {
Msg { param_a: String, param_b: usize },
}
fn receive2(message: Box<ExampleMessage>) {
match *message {
ExampleMessage::Msg { param_a, param_b } => println!("got message"),
}
}
fn main() {}
这是借用检查程序当前实现的限制,并且在启用non-lexical lifetimes时原始代码将按原样运行:
#![feature(nll)]
#[derive(Clone, PartialEq)]
pub enum ExampleMessage {
Msg { param_a: String, param_b: usize },
}
fn receive2(message: Box<ExampleMessage>) {
match *message {
ExampleMessage::Msg { param_a, param_b } => println!("got message"),
}
}
fn main() {}
非词汇生命周期和基于MIR的借阅检查器尚不稳定!
当您与取消引用的值匹配时,该值 not 正常移动。这allows you to do something like:
enum Foo {
One,
Two,
}
fn main() {
let f = &Foo::One;
match *f {
Foo::One => {}
Foo::Two => {}
}
}
在这种情况下,您希望获取Box
1 中的内容的所有权,以便在match
中对字段进行解构时获取字段的所有权。您可以通过在尝试匹配之前将值移出框来实现此目的。
这样做的好方法是:
fn receive2(message: Box<ExampleMessage>) {
let message = *message;
match message {
ExampleMessage::Msg { param_a, param_b } => println!("got message"),
}
}
但你也可以使用花括号强制移动:
fn receive2(message: Box<ExampleMessage>) {
match {*message} {
ExampleMessage::Msg { param_a, param_b } => println!("got message"),
}
}
我不完全理解为什么单个字段会起作用;它确实不一致。我唯一的 guess 是Box
的所有权被移动到第一个参数,提取了参数,然后编译器再次尝试将其移动到下一个参数。
1 - 通过*
移出包含的元素是一种特殊功能,只有Box
支持。例如,如果您尝试使用引用执行此操作,则会得到&#34;无法移出借来的内容&#34;错误。您也无法实现Deref
特征来执行此操作;它是编译器内部的硬编码能力。