在向下转换后模式匹配具有多个值的枚举时使用移动值 [英] Use of moved value when pattern matching an enum with multiple values after downcasting

查看:68
本文介绍了在向下转换后模式匹配具有多个值的枚举时使用移动值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以在具有一个 String 参数的 enum 上使用模式匹配:

I can use pattern matching on an enum that has one String parameter:

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 个参数的枚举执行模式匹配:

And yet I am unable to perform pattern matching on an enum with 2 parameters:

#[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 上进行模式匹配而没有向下转换,这工作正常,但我需要向下转换.这对我来说似乎是很奇怪的行为,我不知道如何规避这个错误.

I tried pattern matching on the same enum without downcasting before, and this works fine but I am required to downcast. This just seems like very strange behavior to me and I don't know how to circumvent this error.

我每晚使用 Rust 1.19.0 (afa1240e5 2017-04-29)

I am using Rust 1.19.0-nightly (afa1240e5 2017-04-29)

推荐答案

我之前尝试过在同一个枚举上进行模式匹配而没有向下转换,这很好用

I tried pattern matching on the same enum without downcasting before, and this works fine

这是减少问题的一个很好的尝试.问题是你减少了太多.将 Box 向下转换为 Foo 不会返回 Foo它返回一个 Box:

This is a good attempt at reducing the problem. The issue is that you reduced too far. Downcasting a Box<T> to a Foo doesn't return a Foo, it returns a Box<Foo>:

fn downcast<T>(self) -> Result<Box<T>, Box<Any + 'static>> 

您可以通过以下方式重现问题:

You can reproduce the problem with:

#[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() {}

好消息

这是借用检查器当前实现的限制,当非词法生存期 已启用:

#![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 的借用检查器还不稳定!

The current reality

Non-lexical lifetimes and the MIR-based borrow checker are not yet stable!

当您匹配取消引用的值时,该值通常移动.这允许您执行类似的操作:

When you match against a dereferenced value, the value is not normally moved. This allows you to do something like:

enum Foo {
    One,
    Two,
}

fn main() {
    let f = &Foo::One;
    match *f {
        Foo::One => {}
        Foo::Two => {}
    }
}

在这种情况下,您希望获得 Box1 中事物的所有权,以便在 match 中对其进行解构时获得字段的所有权.您可以通过尝试匹配它之前将值移出框来实现这一点.

In this case, you wish to take ownership of the thing inside the Box1 in order to take ownership of the fields when destructuring it in the match. You can accomplish this by moving the value out of the box before trying to match on it.

要做到这一点很长:

fn receive2(message: Box<ExampleMessage>) {
    let message = *message;
    match message {
        ExampleMessage::Msg { param_a, param_b } => println!("got message"),
    }
}

但您也可以使用花括号强制移动:

But you can also force the move by using curly braces:

fn receive2(message: Box<ExampleMessage>) {
    match {*message} {
        ExampleMessage::Msg { param_a, param_b } => println!("got message"),
    }
}

我不完全理解为什么单个字段会起作用;这肯定是不一致的.我唯一的猜测Box 的所有权被移动到第一个参数,参数被提取,然后编译器再次尝试将它移动到下一个参数.

I don't fully understand why a single field would work; it's certainly inconsistent. My only guess is that the ownership of the Box is moved to the first param, the param is extracted, then the compiler tries to move it again to the next parameter.

1 — 通过 * 将包含的元素移出是只有 Box 支持的特殊功能.例如,如果您尝试使用参考来执行此操作,则会收到无法移出借用内容"错误.你也不能实现 Deref 特性来做到这一点;这是编译器内部的硬编码能力.

1 — Moving the contained element out via * is a special power that only Box supports. For example, if you try to do this with a reference, you get the "cannot move out of borrowed content" error. You cannot implement the Deref trait to do this either; it's a hard-coded ability inside the compiler.

这篇关于在向下转换后模式匹配具有多个值的枚举时使用移动值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆