如何获得 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" 结构来处理所有这些 Foo
和 Bar
的创建。所以我只希望结构 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
在堆中关闭并且不会四处移动。
我不知道有任何计划支持这种解决方案,但我认为也没有太多的呼声。也许这在技术上什至不可行!
我有两个这样的简单结构:
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" 结构来处理所有这些 Foo
和 Bar
的创建。所以我只希望结构 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
在堆中关闭并且不会四处移动。
我不知道有任何计划支持这种解决方案,但我认为也没有太多的呼声。也许这在技术上什至不可行!