gpt4 book ai didi

rust - 在向下转换后模式匹配具有多个值的枚举时使用移动的值

转载 作者:行者123 更新时间:2023-11-29 08:12:27 25 4
gpt4 key购买 nike

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

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)

最佳答案

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

这是减少问题的一次很好的尝试。问题是你减少太多了。向下转换 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 的借用检查器还不稳定!

当您匹配取消引用的值时,该值通常不会移动。这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"),
}
}

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


1 — 通过 * 将包含的元素移出是一种特殊的力量,只有Box支持。例如,如果您尝试对引用执行此操作,则会出现“无法移出借用的内容”错误。您无法实现 Deref这样做的特质;它是编译器内部的硬编码能力。

关于rust - 在向下转换后模式匹配具有多个值的枚举时使用移动的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43742606/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com