从 Rust 中的枚举中提取盒装枚举

Bha*_*rni 1 enums rust

我正在用 Rust 编写一个类似Scheme 的语言的解释器。我将 AST 编码为枚举:

#[derive(Debug)]
pub enum Object {
    Integer(i64),
    Boolean(bool),
    Character(char),
    String(String),
    Symbol(String),
    Cons { car: Box<Object>, cdr: Box<Object> },
    Nil,
}

pub type ObjectBox = Box<Object>;
Run Code Online (Sandbox Code Playgroud)

我想添加一个car(&self) -> ObjectBox方法到Object. 我想出了:

impl Object {
    pub fn car(&self) -> Option<ObjectBox> {
        match self {
            Object::Cons { car, cdr: _ } => Some(ObjectBox::new(**car)),
            _ => None,
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编译时我收到此错误:

error[E0507]: cannot move out of `**car` which is behind a shared reference
  --> src/core/object.rs:94:65
   |
94 |             Object::Cons { car, cdr: _ } => Some(ObjectBox::new(**car)),
   |                                                                 ^^^^^ move occurs because `**car` has type `object::Object`, which does not implement the `Copy` trait

For more information about this error, try `rustc --explain E0507`.
Run Code Online (Sandbox Code Playgroud)

我明白为什么会发生错误,但我无法想出解决方法。Object我当前的实现可以做到这一点吗?

Net*_*ave 5

您无法移出 a &self,因此您几乎没有选择:

  1. 消耗self
impl Object {
    pub fn car(self) -> Option<ObjectBox> {
        match self {
            Object::Cons { car, cdr: _ } => Some(ObjectBox::new(*car)),
            _ => None,
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

操场

  1. 返回参考:
pub type ObjectBox<'a> = Box<&'a Object>;

impl Object {
    pub fn car(&self) -> Option<ObjectBox> {
        match self {
            Object::Cons { car, cdr: _ } => Some(ObjectBox::new(car.as_ref())),
            _ => None,
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

操场

  1. 克隆您需要的内容:
#[derive(Debug, Clone)]
pub enum Object {
    Integer(i64),
    Boolean(bool),
    Character(char),
    String(String),
    Symbol(String),
    Cons { car: Box<Object>, cdr: Box<Object> },
    Nil,
}

pub type ObjectBox = Box<Object>;

impl Object {
    pub fn car(&self) -> Option<ObjectBox> {
        match self {
            Object::Cons { car, cdr: _ } => Some(ObjectBox::new(*car.clone())),
            _ => None,
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

操场

3.1 正如@KevinReid所建议的,您可以更改BoxRc,这样您就可以获得指向该对象的廉价可克隆指针:

use std::rc::Rc;

#[derive(Debug, Clone)]
pub enum Object {
    Integer(i64),
    Boolean(bool),
    Character(char),
    String(String),
    Symbol(String),
    Cons { car: ObjectBox, cdr: ObjectBox },
    Nil,
}

pub type ObjectBox = Rc<Object>;

impl Object {
    pub fn car(&self) -> Option<ObjectBox> {
        match self {
            Object::Cons { car, cdr: _ } => Some(car.clone()),
            _ => None,
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

操场