Rust 我对支持Rc或包装盒类型的锈蚀向量的理解是否正确?

Rust 我对支持Rc或包装盒类型的锈蚀向量的理解是否正确?,rust,borrow-checker,Rust,Borrow Checker,我不是在找代码示例。我想陈述我对Box vs.Rc的理解,让你告诉我我的理解是对还是错 假设我有一个traitChattyAnimal和一个实现这个trait的structCat,例如 pub trait ChattyAnimal { fn make_sound(&self); } pub struct Cat { pub name: String, pub sound: String } impl ChattyAnimal for Cat { fn make_sou

我不是在找代码示例。我想陈述我对Box vs.Rc的理解,让你告诉我我的理解是对还是错

假设我有一个trait
ChattyAnimal
和一个实现这个trait的struct
Cat
,例如

pub trait ChattyAnimal {
  fn make_sound(&self);
}

pub struct Cat {
  pub name: String,
  pub sound: String
}

impl ChattyAnimal for Cat {
  fn make_sound(&self) {
    println!("Meow!");
  }
}
现在让我们假设我还有其他结构(狗、牛、鸡等),它们也实现了
ChattyAnimal
特性,并且假设我想将所有这些存储在同一个向量中

因此,第一步是我必须使用Box类型,因为Rust编译器无法确定可能实现此特性的所有内容的大小。因此,我们必须使用<代码> box 类型将这些损坏的东西存储在堆中,这就像C++中的一个更聪明的指针。任何用盒子包裹的东西一旦超出范围就会被铁锈自动删除

// I can alias and use my Box type that wraps the trait like this:
pub type BoxyChattyAnimal = Box<dyn ChattyAnimal>;

// and then I can use my type alias, i.e.
pub struct Container {
  animals: Vec<BoxyChattyAnimal>
}
一个重要的收获是,如果我想要一个特征类型的向量,我需要显式地将该向量的类型设置为一个包装我的特征的框或Rc。因此,Rust语言设计者迫使我们提前考虑这一点,这样一个Box或Rc就不会(至少不会轻易或意外地)在同一个向量中结束


这感觉像是一个经过深思熟虑的设计——帮助我避免在代码中引入bug。我的上述理解正确吗?

是的,所有这些都是正确的

这种设计还有第二个原因:它允许编译器验证您在向量元素上执行的操作是否以安全的方式使用内存,与它们的存储方式相关

例如,如果您在
ChattyAnimal
上有一个变异动物的方法(即采用
&mut self
参数),您可以在
Vec
的元素上调用该方法,只要您对该向量有一个可变的引用;Rust编译器会知道,只有一个引用指向所讨论的
ChattyAnimal
(因为唯一的引用位于
Box
内,该框位于
Vec
内,并且您有一个对
Vec
的可变引用,因此不能有任何其他引用)。如果您试图用
Vec
编写相同的代码,编译器会抱怨;它不能完全消除你的代码可能会变异动物的可能性,因为它的代码叫它在试图读取动物的中间,这可能会导致一些不一致的调用代码。 因此,编译器需要知道
Vec
的所有元素都以相同的方式处理其内存,以便它可以检查以确保对
Vec
的某个任意元素的引用被正确使用


(还有第三个原因,那就是性能;因为编译器知道这是一个“Boxes的向量”或“Rcs的向量”,它可以生成采用特定存储机制的代码。例如,如果您有一个向量
Rc
s,并且
clone
其中一个元素,编译器生成的机器代码只需转到向量中列出的内存地址并将1添加到存储在其中的引用计数即可工作,无需这样做如果允许向量混合不同的分配方案,生成的代码就必须复杂得多,因为它不能假设“存在引用计数”,而是需要(在运行时)找到处理正在使用的内存分配方案的适当代码段,然后运行它;这样会慢得多。)

似乎很正确!这也是一件小事,在将来,这类问题可能更适合于users.rust-lang.org上的论坛。
pub type RcChattyAnimal = Rc<dyn ChattyAnimal>;

pub struct Container {
  animals: Vec<RcChattyAnimal>
}