模式匹配后保存Vec

时间:2017-05-02 08:37:44

标签: rust pattern-matching message-passing

我使用机器人包装箱中的Actor特性:

extern crate robots;    

use std::any::Any;
use robots::actors::{Actor, ActorCell};


#[derive(Clone, PartialEq)]
pub enum ExampleMessage {
    Test { data: Vec<u8> },
}

pub struct Dummy {
    data: Vec<u8>,
}

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::Test { data } => {
                    self.data = data; // cannot assign to immutable field
                    println!("got message")
                }
            }
        }
    }
}

impl Dummy {
    pub fn new(_: ()) -> Dummy {
        let data = Vec::new();
        Dummy { data }
    }
}

错误:

error: cannot assign to immutable field `self.data`
  --> <anon>:18:21
   |
18 |                     self.data = data; // cannot assign to immutable field
   |                     ^^^^^^^^^^^^^^^^

我理解为什么我当前的代码不起作用,但我不知道保存传入数据(Vec)的最佳方法是什么,以便我的Dummy可以在以后访问它。

2 个答案:

答案 0 :(得分:1)

您在此处缺少一个简单的要点:您的方法receive()获取&self作为参数。您无法通过self修改&self对象,因为它是不可变引用。要更改self的任何字段,请接受可变引用(&mut self)或 - 如果无法绕过它 - 使用内部可变性。例如:

fn receive(&mut self, message: Box<Any>) {
    // ...
    self.data = data;  // works
    // ...
}

但如果您无法更改Actor实施的特征Dummy,则可能无法进行此操作。在这种情况下,您 使用interior mutability,例如RefCell<Vec<u8>>。但如果你能改变这个特性,可以考虑这样做。方法receive()听起来似乎应该更改self对象以使其具有任何效果。

如果这不仅仅是一个粗心的错误,请务必阅读Rust书中BorrowingMutability的章节,因为这对Rust非常重要。

答案 1 :(得分:0)

我在RobotS github repo中找到了一个test,它显示了如何管理Actor的内部状态。 状态必须封装在Mutex内以进行线程安全访问:

extern crate robots;    

use std::any::Any;
use std::sync::Mutex;
use robots::actors::{Actor, ActorCell};


#[derive(Clone, PartialEq)]
pub enum ExampleMessage {
    Test { data: Vec<u8> },
}

pub struct Dummy {
    data: Mutex<Vec<u8>>,
}

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::Test { data } => {
                    let mut my_data = self.data.lock().unwrap();
                    *my_data = data;
                    println!("got message")
                }
            }
        }
    }
}

impl Dummy {
    pub fn new(_: ()) -> Dummy {
        let data = Mutex::new(Vec::new());
        Dummy { data }
    }
}