Rust 如何共享堆分配的trait对象?

Rust 如何共享堆分配的trait对象?,rust,traits,trait-objects,Rust,Traits,Trait Objects,我有一个trait和一个实现该trait的结构(trait对象)。我想在堆上分配我的trait对象,并让其他结构引用它们 箱场 这也是可行的,但据我所知,我的材料将在堆栈而不是堆上分配。如果Material的值真的很大,我宁愿把它放在堆上,那该怎么办?这就引出了下一种不编译的方法: 对方框的引用 struct Sphere src/main.rs:16:19 | 16 |材料:m1, |^^预期特征材料,发现结构“Iron”` | =注意:预期类型为“&std::boxed::BoxRc或Arc

我有一个trait和一个实现该trait的结构(trait对象)。我想在堆上分配我的trait对象,并让其他结构引用它们

箱场 这也是可行的,但据我所知,我的
材料将在堆栈而不是堆上分配。如果
Material
的值真的很大,我宁愿把它放在堆上,那该怎么办?这就引出了下一种不编译的方法:

对方框的引用
struct Sphere src/main.rs:16:19
|
16 |材料:m1,
|^^预期特征材料,发现结构“Iron”`
|
=注意:预期类型为“&std::boxed::Box
Rc
Arc
当您需要共享所有权时,
Rc
Arc
通常是第一个需要的工具。这些类型通过引用计数实现共享,因此克隆一个是便宜的(只需复制指针并增加refcount)。在这种情况下,两种方法中的任何一种都可以很方便地工作:

struct Sphere {
    radius: f64,
    material: Rc<dyn Material>,
}

let m1 = Rc::new(Iron {});
let s1 = Sphere {
    radius: 1.0,
    material: m1,
};
这甚至比使用
Rc
更便宜,因为
&
引用可以
复制
但即使
本身存储在堆上,指向它的引用仍然绑定到堆栈变量
m1
的生存期。如果你不能让
m1
活得足够长,你可能会想使用
Rc
而不是普通的引用

框的引用
这种方法也应该有效,尽管它是不必要的。原因是,虽然可以将
强制为
,但不能将
强制为
;这些类型不兼容。相反,您需要创建类型为
Box
的堆栈变量,以便可以引用它

let m1: Box<dyn Material> = Box::new(Iron {}); // coercion happens here
let s1 = Sphere {
    radius: 1.0,
    material: &m1,  // so that this reference is the right type
};
让m1:Box=Box::new(Iron{});//强迫在这里发生
设s1=球面{
半径:1.0,
材质:&m1,//因此此引用是正确的类型
};

@diing\u sphynx我添加了一些解释。我认为还有另一个问题更详细地解释了为什么
&T
->
&dyn Trait
是一种有效的强制,而
&Box
->
&Box
不是;如果我能找到它,我会链接到它。还有一件有趣的事:在您的完整示例中,我尝试内联调用
Rc::clone
,但没有成功(失败的原因与您在最后提到的强制引用相同)。但是当我使用
m1.clone()
而不是
Rc::clone(&m1)
时,它起了作用。这是出乎意料的,因为我认为,
Rc::clone(&x)
x.clone()
应该是一样的:@diing\u sphynx我认为这是因为它们之间的区别(在本例中是未大小化的强制,而不是解除强制)
m1.clone()
将始终解析为
m1
的类型,即
Rc
。但是
Rc::clone(&m1)
需要推断
Rc
的参数,并且它不知道强制需要在函数调用的“外部”发生,因此它选择了错误的东西(
Rc
而不是
Rc
)。我尝试了您的建议,并引用了以下内容:
&*m1
通过创建对方框内容的引用,效果非常好,但在这种情况下,仅使用
&m1
似乎不起作用:
struct Sphere<'a> {
    radius: f64,
    material: &'a Box<dyn Material>,
}

fn main() {
    let m1 = &Box::new(Iron {});
    let s1 = Sphere {
        radius: 1.0,
        material: m1,
    };
    assert_eq!(s1.radius, 1.0);
}
error[E0308]: mismatched types
  --> src/main.rs:16:19
   |
16 |         material: m1,
   |                   ^^ expected trait Material, found struct `Iron`
   |
   = note: expected type `&std::boxed::Box<(dyn Material + 'static)>`
              found type `&std::boxed::Box<Iron>`
struct Sphere {
    radius: f64,
    material: Rc<dyn Material>,
}

let m1 = Rc::new(Iron {});
let s1 = Sphere {
    radius: 1.0,
    material: m1,
};
struct Sphere<'a> {
    radius: f64,
    material: &'a dyn Material,
}

let m1 = Box::new(Iron {});
let s1 = Sphere {
    radius: 1.0,
    material: &*m1, // dereference the `Box` and get a reference to the inside
};
let s2 = Sphere {
    radius: 2.0,
    material: &*m1,
};
let m1: Box<dyn Material> = Box::new(Iron {}); // coercion happens here
let s1 = Sphere {
    radius: 1.0,
    material: &m1,  // so that this reference is the right type
};