如何获得C ++初始化列表的等价物

时间:2015-01-22 14:36:43

标签: rust

我有两个简单的结构:

struct Foo {
}

struct Bar<'a> {
    foo: &'a mut Foo;
}

impl Foo {
    pub fn new() -> Foo {
        Foo
    }
}

impl<'a> Bar<'a> {
    pub fn new(foo: &'a mut Foo) -> Bar<'a> {
        Bar {
            foo: foo,
        }
    }
}

所以基本上结构Bar需要引用Foo来处理。这就是我使用它的方式:

let mut foo = Foo::new();
let mut bar = Bar::new(&mut foo);

现在我想创建一个“粘合”结构来处理所有这些FooBar的创建。所以我只希望结构Container有1 Foo,1 Bar

我尝试过这样的事情:

impl Container {
    pub fn new() -> Container {
        Container {
          foo: Foo::new(),
          bar: Bar::new(&mut foo),
        }
    }
}

但它不起作用,我无法从foo初始值设定项中引用字段bar。 我基本上想模仿以下C ++代码:

Container::Container() :
    foo(),
    bar(&foo)
{}

关于如何解决这个问题的任何想法?当然,使用任何类型的动态分配/引用计数都会非常过分。

---编辑---

要清楚,我想创建与此C ++代码段等效的Rust代码:

struct Foo {
};

struct Bar {
    Bar(Foo& f) : foo(f) {}
    Foo& foo;
};

Foo f;
Bar b(f);

struct Container {
    Container() : f(), b(f) {}
    Foo f;
    Bar b;
};

---编辑---

以下是我最终使用的Rc<>

use std::rc::Rc;

struct Foo {
  pub bar: Rc<Bar>,
}

impl Foo {
  pub fn new(bar: Rc<Bar>) -> Foo {
    Foo {
      bar: bar,
    }
  }
}

struct Bar {
  a: u8,
}

impl Bar {
  pub fn new() -> Bar {
    Bar {
      a: 42,
    }
  }
}

struct Container {
  pub bar: Rc<Bar>,
  pub foo: Foo,
}

impl Container {
  pub fn new() -> Container {
    let bar = Rc::new(Bar::new());
    Container {
      bar: bar.clone(),
      foo: Foo::new(bar.clone()),
    }
  }
}

fn main() {
  // Just checking that we get the same bar for both
  // inside Container and inside Foo
  let c = Container::new();
  println!("{:p}", &*c.bar);
  println!("{:p}", &*c.foo.bar);

  // So from what I understand, here bar is on the stack
  // then byte-copied to the heap where that Rc<> will point?
  let bar = Bar::new();
  println!("{:p}", &bar);
  let foo = Foo::new(Rc::new(bar));
  println!("{:p}", &*foo.bar);

  // Sad story is that using this Rc<> I now use the "cuteness"
  // and safety that I had with reference borrowing:
  // struct Foo<'a> {
  //   bar: &'a mut Bar,
  // }
  // impl<'a> Foo<'a> {
  //   pub fn new(bar: &'a Bar) -> Foo<'a> {
  //     Foo { bar: bar }
  //   }
  // }
  // let bar = Bar::new();
  // let foo = Foo::new(&bar);
}

但这并不令人满意,我觉得我用机枪杀了一只兔子。任何见解都非常感激:(

2 个答案:

答案 0 :(得分:2)

无法在Rust中的安全代码中表达此概念。

答案 1 :(得分:1)

考虑这种简化的记忆观。我编写尺寸和偏移来说明问题,它们与现实没有任何相似之处。

我们首先通过堆栈分配一个全新的Container,其中包含您在地址80处所需的结构。

80 Container
..   foo: Foo (size 8)
88   bar: Bar
       foo: &Foo (size 8, value 80)

现在我们按值将结构传递给一个方法,或者从我们创建它的地方返回它,就像构造函数一样。按值移动涉及逐位复制,因此我们将其移至地址40:

40 Container
..   foo: Foo (size 8)
48   bar: Bar
       foo: &Foo (size 8, value 80)
哦,哦!内部foo现在指向一段记忆不再是我们结构的一部分!这是Rust试图阻止的不安全代码的类型。

从概念上讲,有一些方法可以防止这种情况发生。 Rust可以跟踪指针实际上只是某个偏移量,然后每次移动项目时重写该值。我不知道,但这看起来很贵。它可能还需要一些特殊的语法来表示它。

我希望看到的解决方案涉及间接和堆。如果我们堆分配顶级foo 并且Rust分别跟踪堆栈和堆生存期,那么我们可能会有类似的东西:

== stack
80 Container
..   foo: Box<Foo> (size 8, value 10)
88   bar: Bar
       foo: &Foo (size 8, value 10)

== heap
10 Foo (size 8) 

移动结构会改变地址,但是这个值会安然无恙,因为Foo在堆中关闭而不会移动。

我不知道有任何支持这种解决方案的计划,但我也不认为它有很大的喧嚣。也许它甚至在技术上都不可行!