Rust 创建递归枚举--我应该使用生存期引用吗?(锈迹)

Rust 创建递归枚举--我应该使用生存期引用吗?(锈迹),rust,reference,lifetime,algebraic-data-types,Rust,Reference,Lifetime,Algebraic Data Types,我想创建一个ADT,如: 发布枚举谓词,框), Bool(LogicOp、Literal、Literal) } 但显然,这不是指定寿命的正确方法 我的问题有两个方面: 在这里定义寿命的正确方法是什么 有没有更好的办法来解决这个问题? 我不想每次都克隆所有内容,因为所有内容都是不可变的,而且我不想创建多个副本。我还想做一些事情,比如 let foo=Predicate::Bool(无论参数是什么); let and=谓词::and(&foo,&foo); let neg=谓词::neg(&and

我想创建一个ADT,如:

发布枚举谓词,框),
Bool(LogicOp、Literal、Literal)
}
但显然,这不是指定寿命的正确方法

我的问题有两个方面:

  • 在这里定义寿命的正确方法是什么
  • 有没有更好的办法来解决这个问题? 我不想每次都克隆所有内容,因为所有内容都是不可变的,而且我不想创建多个副本。我还想做一些事情,比如
  • let foo=Predicate::Bool(无论参数是什么);
    let and=谓词::and(&foo,&foo);
    let neg=谓词::neg(&and);
    设bar=谓词::And(&And,&neg);
    

    以此类推,以后继续能够使用
    foo
    以及
    neg

    如果一切都是不变的,那么处理这种情况的最简单方法就是使用
    Rc
    /
    Arc
    (两者之间的唯一区别是后者可用于从多个线程访问的对象。)您可以按如下方式定义枚举:

    pub enum Predicate {
        And(Rc<Predicate>, Rc<Predicate>),
        Neg(Rc<Predicate>),
        Bool(LogicOp, Literal, Literal)
    }
    
    (从技术上讲,如果您不打算在以后使用,例如,
    neg
    ,则并非所有这些克隆都是必需的。)

    简化此样板文件的一种方法是使用
    谓词
    类型上的方法或相关函数来创建pre-
    Rc
    ed值,如下所示:

    impl Predicate {
        pub fn and(a: &Rc<Predicate>, b: &Rc<Predicate>) -> Rc<Predicate> {
            Rc::new(Predicate::And(a.clone(), b.clone())
        }
    
        pub fn neg(a: &Rc<Predicate>) -> Rc<Predicate> {
            Rc::new(Predicate::Neg(a.clone()))
        }
    
        pub fn boolean(op: LogicOp, a: Literal, b: Literal) -> Rc<Predicate> {
            Rc::new(Predicate::Bool(op, a, b))
        }
    }
    

    但是,这种方法有一个不可避免的缺点。如果不首先取消引用,就无法通过
    Rc
    匹配
    ,这会使使用
    Rc
    ADT有些痛苦。请参阅以了解详细信息。

    但显然这不是指定生命周期的正确方法。-您尝试过类似的方法吗:谢谢你!这看起来有点笨拙,来自Haskell…但我想当你对堆栈和堆有显式控制时,这是没有帮助的
    impl Predicate {
        pub fn and(a: &Rc<Predicate>, b: &Rc<Predicate>) -> Rc<Predicate> {
            Rc::new(Predicate::And(a.clone(), b.clone())
        }
    
        pub fn neg(a: &Rc<Predicate>) -> Rc<Predicate> {
            Rc::new(Predicate::Neg(a.clone()))
        }
    
        pub fn boolean(op: LogicOp, a: Literal, b: Literal) -> Rc<Predicate> {
            Rc::new(Predicate::Bool(op, a, b))
        }
    }
    
    let foo = Predicate::boolean(whatever args);
    let and = Predicate::and(&foo, &foo);
    let neg = Predicate::neg(&and);
    let bar = Predicate::and(&and, &neg);