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

How to get the equivalent of C++ initializer lists

我有两个这样的简单结构:

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);

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

我试过做类似的事情:

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

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

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

关于如何解决这个问题有什么想法吗?当然,在这里使用任何一种动态 allocation/reference 计数都太过分了。

--- 编辑 ---

明确地说,我想创建与此 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);
}

但这真的不太令人满意,我觉得我用机关枪杀死了一只兔子。非常感谢任何见解:(

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

考虑一下这个简化的内存视图。我正在编造尺寸和偏移量来说明问题,它们与现实没有任何相似之处。

我们首先在地址 80 处分配一个全新的 Container 和您想要的结构。

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

现在我们按值将结构传递给一个方法,或者 return 从我们创建它的地方传递它,就像构造函数一样。按值移动涉及逐位复制,所以让我们将其移动到地址 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 在堆中关闭并且不会四处移动。

我不知道有任何计划支持这种解决方案,但我认为也没有太多的呼声。也许这在技术上什至不可行!