TL; DR 如何在引用共享底层数据的泛型类型上构建数据结构?
这个问题与Rust中的语义和良好的数据建模有关。下面的代码是对我的问题的一个(更多)微不足道的提炼,以突出我的具体问题,而不是我的实际代码。
目标是创建一个函数,构建几个包含对泛型类型共享数据的引用的向量。在以下示例的命名法中,我希望能够返回可以存储Struct1
和Struct2
的向量集合(由特征Trait
抽象),但是因为(在我的真实代码中)Struct1
和Struct2
相对较大并且将相对频繁地存储在相对较多的地方,我宁愿存储对共享数据的引用,而不是将它们全部复制到那里。
我面临的当前问题(并且有许多中间修订)是:
Trait
,而不是Sized
我需要在我的向量中存储引用&
引用build_vectors
函数的范围。
Traits
的全局向量来解决这个问题,我可以在其中指出引用,遗憾的是上面的问题(1)似乎排除了该策略。
struct Struct1;
struct Struct2;
trait Trait { fn name(&self) -> &str; }
impl Trait for Struct1 { fn name(&self) -> &str { "Struct1" } }
impl Trait for Struct2 { fn name(&self) -> &str { "Struct2" } }
fn shallow_copy<'a>(v: &'a Vec<&'a Box<Trait>>) -> Vec<&'a Box<Trait>> {
v.iter().map(|x|*x).collect()
}
fn build_vectors<'a>() -> (Vec<&'a Box<Trait>>, Vec<&'a Box<Trait>>) {
let box_struct1: &Box<Trait> = &(Box::new(Struct1) as Box<Trait>);
let box_struct2: &Box<Trait> = &(Box::new(Struct2) as Box<Trait>);
let vec1: Vec<&Box<Trait>> = vec![box_struct1];
let mut vec2: Vec<&Box<Trait>> = shallow_copy(&vec1);
vec2.push(box_struct2);
(vec1, vec2)
}
fn join_names(v: &Vec<&Box<Trait>>) -> String {
v.iter().map(|s| s.name()).collect::<Vec<_>>().connect(" ")
}
fn main() {
let (vec1, vec2) = build_vectors();
println!("vec1: {}", join_names(&vec1));
println!("vec2: {}", join_names(&vec2));
}
所需的输出是:
vec1: Struct1
vec2: Struct1 Struct2
答案 0 :(得分:6)
这听起来像Rc
的完美用例。 Rc
是一种引用计数类型,允许您将多个所有者设为相同的值。
use std::rc::Rc;
struct Struct1;
struct Struct2;
trait Trait { fn name(&self) -> &str; }
impl Trait for Struct1 { fn name(&self) -> &str { "Struct1" } }
impl Trait for Struct2 { fn name(&self) -> &str { "Struct2" } }
fn shallow_copy<'a>(v: &[Rc<Trait + 'a>]) -> Vec<Rc<Trait + 'a>> {
v.iter().map(|x| x.clone()).collect()
}
fn build_vectors() -> (Vec<Rc<Trait>>, Vec<Rc<Trait>>) {
let vec1: Vec<Rc<Trait>> = vec![Rc::new(Struct1)];
let mut vec2: Vec<Rc<Trait>> = shallow_copy(&vec1);
vec2.push(Rc::new(Struct2));
(vec1, vec2)
}
fn join_names<'a>(v: &[Rc<Trait + 'a>]) -> String {
v.iter().map(|s| s.name()).collect::<Vec<_>>().connect(" ")
}
fn main() {
let (vec1, vec2) = build_vectors();
println!("vec1: {}", join_names(&vec1));
println!("vec2: {}", join_names(&vec2));
}
请注意,shallow_copy
中的结尾使用clone()
来克隆Rc
。克隆Rc
会创建一个指向相同值的新Rc
(基础值不克隆),共享引用计数增加1.删除{ {1}}递减引用计数,当引用计数降为零时,基础值将被删除。
顺便说一句,我已经改变了一些函数来获取切片引用而不是Rc
引用,因为它使函数更通用(例如,你也可以从数组中获取切片)。
另外,我必须使用生命周期来注释特征对象,因为没有注释,编译器会假定Vec
(即'static
),这意味着&#34; {{1}的实现}它不包含任何借用的指针(短于Trait + 'static
)&#34;,这会导致生命周期错误。