1

我刚开始使用 Rust,但不能完全掌握生命周期,所以我可以自己解决以下问题:

这个测试项目是关于模拟一点,以允许通过各种按位操作对其进行跟踪,例如let newbit = oldbit1 ^ oldbit2,然后看newbit我可以告诉它来自一个 XOR 操作,其中oldbit1oldbit2作为操作数。

#[derive(Copy,Clone)]
pub enum TraceOperation {
        AND,
        OR,
        XOR,
        NOT,
}

#[derive(Copy,Clone)]
pub struct TraceBit<'a> {
        source_a: Option<&'a TraceBit<'a>>,
        source_b: Option<&'a TraceBit<'a>>,
        source_op: Option<TraceOperation>,
        value: bool,
}

这可以编译,但我不完全理解为什么需要这样的生命周期参数。我假设编译器不能期望成员source_asource_b结构本身一样长,因为这可能不成立,因此需要明确的生命周期。

  • 这个假设正确吗?

此外,我不完全理解为什么我必须重新指定引用类型的生命周期参数,即为什么我必须写source_a: Option<&'a TraceBit<'a>>而不是source_a: Option<&'a TraceBit>.

  • 第二个生命周期是用来做什么的?我如何大声读出那句话?我有: "source_a 是一个类型的变量,Option它可能具有对"的实例的Some引用(至少与 struct 本身和 member 一样有效)source_bTraceBit

我的最后一个问题是我无法使用重载运算符使其工作:

use std::ops::BitXor;
impl<'a> BitXor for TraceBit<'a> {
        type Output = Self;
        fn bitxor(self, rhs: Self) -> Self {
                let valA: usize = if self.value { 1 } else { 0 };
                let valB: usize = if rhs.value { 1 } else { 0 };
                let val = if valA ^ valB != 0 { true } else { false };
                TraceBit { source_a: Some(&self), source_b: Some(&rhs), source_op: Some(TraceOperation::XOR), value: val }
        }
}

这基本上是基于BitXor 文档的纯粹猜测。因此,我尝试以非常明确的方式对两个输入变量执行异或运算,并创建一个新TraceBit的作为输出,并将其中存储的输入作为参考。

error[E0597]: `self` does not live long enough
  --> libbittrace/src/lib.rs:37:30
   |
37 |   TraceBit { source_a: Some(&self), source_b: Some(&rhs), source_op: Some(TraceOperation::XOR), value: val }
   |                              ^^^^ does not live long enough
38 |  }
   |  - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 31:1...
  --> libbittrace/src/lib.rs:31:1
   |
31 | / impl<'a> BitXor for TraceBit<'a> {
32 | |  type Output = Self;
33 | |  fn bitxor(self, rhs: Self) -> Self {
34 | |   let valA: usize = if self.value { 1 } else { 0 };
...  |
40 | |
41 | | }
   | |_^

error[E0597]: `rhs` does not live long enough
  --> libbittrace/src/lib.rs:37:53
   |
37 |   TraceBit { source_a: Some(&self), source_b: Some(&rhs), source_op: Some(TraceOperation::XOR), value: val }
   |                                                     ^^^ does not live long enough
38 |  }
   |  - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 31:1...
  --> libbittrace/src/lib.rs:31:1
   |
31 | / impl<'a> BitXor for TraceBit<'a> {
32 | |  type Output = Self;
33 | |  fn bitxor(self, rhs: Self) -> Self {
34 | |   let valA: usize = if self.value { 1 } else { 0 };
...  |
40 | |
41 | | }
   | |_^

error: aborting due to 2 previous errors
  • 似乎没有什么比 xor 操作本身更长寿,但我该如何解决这个问题?

我已经尝试了各种解决方法/更改代码,但无济于事,无论如何我宁愿理解问题而不是猜测正确的解决方案......

4

2 回答 2

0

树状结构必须使用Box指针类型 ( Option<Box<TraceBit>>)。一般来说,在结构中你应该更喜欢拥有的类型。

Rust 引用不仅仅是指针。它们是必须在其他地方拥有的数据的借用(编译时读/写锁)。

因此,如果您拥有以下版本TraceBit

pub struct TraceBit {
    source_a: Option<Box<TraceBit>>,
}

那么对它的引用是 type: &'a TraceBit,但是对类型的引用不会改变类型内部的外观,所以类型source_a仍然是Box<TraceBit>。您可以&'a TraceBit逐步递归地获取引用:

trace_bit = trace_bit.source_a.as_ref().unwrap();

但是在 Rust 中,没有任何结构可以对树的根进行引用突然将整个树更改为引用树,因此您创建的类型不存在,这就是您无法正确获得类型注释的原因。

于 2017-12-27T15:26:10.747 回答
0

也许您应该使用包含且可克隆的名称类型,而不是传递引用。

use std::rc::Rc;

#[derive(Debug)]
pub enum TraceOperation {
    AND,
    OR,
    XOR,
    NOT,
}

#[derive(Debug)]
pub enum BitName<T> {
    Name(Rc<T>),
    Combination(Rc<(TraceOperation, BitName<T>, BitName<T>)>),
}

impl<T> Clone for BitName<T> {
    fn clone(&self) -> Self {
        match self {
            &BitName::Name(ref x) => BitName::Name(Rc::clone(x)),
            &BitName::Combination(ref x) => BitName::Combination(Rc::clone(x)),

        }
    }
}

impl<T> From<T> for BitName<T> {
    fn from(x:T) -> Self {
        BitName::Name(Rc::new(x))
    }
}

impl<T> BitName<T> {
    pub fn combine(op : TraceOperation, a : &Self, b :&Self) -> Self {
        BitName::Combination(Rc::new((op, (*a).clone(), (*b).clone())))
    }
}

fn main() {
    let x : BitName<String> = BitName::from(String::from("x"));
    let y : BitName<String> = BitName::from(String::from("y"));
    let xandy = BitName::combine(TraceOperation::AND, &x, &y);
    println!("{:?}", xandy);
}
于 2017-12-27T20:41:04.110 回答