将嵌套特征实例存储在通用变量中
Storing a nested trait instance in a generic variable
如果我有一个具有通用泛型类型的“外部”特征(Collection
,如下),那么我可以创建一个具有“内部”特征类型的实例(Collection<&dyn Stringable>
) .然后我可以对该实例使用任何值,只要这些值实现嵌套特征 (Stringable
):
fn main() {
let mut vs: &mut Collection<&dyn Stringable> = &mut vec![];
vs.add(&1);
vs.add(&true);
vs.add(&3);
for v in vs.get_all() {
println!("{}", v.string());
}
}
trait Collection<T> {
fn add(&mut self, v: T);
fn get_all(&self) -> &Vec<T>;
}
impl<T> Collection<T> for Vec<T> {
fn add(&mut self, v: T) {
self.push(v)
}
fn get_all(&self) -> &Vec<T> {
&self
}
}
trait Stringable {
fn string(&self) -> String;
}
impl Stringable for i8 {
fn string(&self) -> String {
format!("int({})", self)
}
}
impl Stringable for bool {
fn string(&self) -> String {
format!("bool({})", self)
}
}
但是,如果我同时为一个类型 (Collection<i8>
) 实现了外部特征和内部特征,则该类型的值不能放入 Collection<&dyn Stringable>
变量中,即使内部特征第一个 (i8
) 的类型实现了第二个 (Stringable
)。下面的代码给出了以下错误:
the trait `Collection<&dyn Stringable>` is not implemented for `StaticCollection`
代码:
fn main() {
let mut vs: &mut Collection<&dyn Stringable> = &mut StaticCollection{};
for v in vs.get_all() {
println!("{}", v.string());
}
}
struct StaticCollection {}
impl Collection<i8> for StaticCollection {
fn add(&mut self, v: i8) {}
fn get_all(&self) -> &Vec<i8> {
&vec![1, 2, 3]
}
}
是否可以,例如,写类似 impl Collection<&dyn Stringable> for StaticCollection
的东西,以便 StaticCollection
可以存储在通用 Collection<&dyn Stringable>
变量中?
这取决于StaticCollection
如何实现,但技术上是可行的:
impl<'a> Collection<&'a dyn Stringable> for StaticCollection {
fn add(&mut self, v: &'a dyn Stringable) {
}
fn get_all(&self) -> &Vec<&'a dyn Stringable> {
panic!()
}
}
但是 StaticCollection
必须使用 &dyn Stringable
项创建。
例如 (Link to playground):
fn main() {
let mut vs: &mut Collection<&dyn Stringable> = &mut StaticCollection {
v: vec![&0,&1,&2]
};
for v in vs.get_all() {
println!("{}", v.string());
}
}
struct StaticCollection {
v: Vec<&'static dyn Stringable>,
}
impl<'a> Collection<&'a dyn Stringable> for StaticCollection {
fn add(&mut self, v: &'a dyn Stringable) {
}
fn get_all(&self) -> &Vec<&'a dyn Stringable> {
&self.v
}
}
请注意,我们在 'a
生命周期内是通用的,这是针对 Vec
的 项 ,但是因为特征(如定义的那样) 需要 get_all
到 return 从 self
借来的 &Vec
,不可能“改造” Vec
。所以如果你定义了StaticCollection { v: Vec<&i8> }
(或者Vec<i8>
,get_all
就无法实现(不“泄露”一个新的Vec
,这可能不是你想要的)。
get_all
的完整生命周期实际上是:
fn get_all<'s>(&'s self) -> &'s Vec<&'a ...>
一句警告:dyn Trait
可能会让您在使用编译器和借用检查器时陷入困境。
您可能还想查看 this blog post 探索类似概念的“类型族”。
如果我有一个具有通用泛型类型的“外部”特征(Collection
,如下),那么我可以创建一个具有“内部”特征类型的实例(Collection<&dyn Stringable>
) .然后我可以对该实例使用任何值,只要这些值实现嵌套特征 (Stringable
):
fn main() {
let mut vs: &mut Collection<&dyn Stringable> = &mut vec![];
vs.add(&1);
vs.add(&true);
vs.add(&3);
for v in vs.get_all() {
println!("{}", v.string());
}
}
trait Collection<T> {
fn add(&mut self, v: T);
fn get_all(&self) -> &Vec<T>;
}
impl<T> Collection<T> for Vec<T> {
fn add(&mut self, v: T) {
self.push(v)
}
fn get_all(&self) -> &Vec<T> {
&self
}
}
trait Stringable {
fn string(&self) -> String;
}
impl Stringable for i8 {
fn string(&self) -> String {
format!("int({})", self)
}
}
impl Stringable for bool {
fn string(&self) -> String {
format!("bool({})", self)
}
}
但是,如果我同时为一个类型 (Collection<i8>
) 实现了外部特征和内部特征,则该类型的值不能放入 Collection<&dyn Stringable>
变量中,即使内部特征第一个 (i8
) 的类型实现了第二个 (Stringable
)。下面的代码给出了以下错误:
the trait `Collection<&dyn Stringable>` is not implemented for `StaticCollection`
代码:
fn main() {
let mut vs: &mut Collection<&dyn Stringable> = &mut StaticCollection{};
for v in vs.get_all() {
println!("{}", v.string());
}
}
struct StaticCollection {}
impl Collection<i8> for StaticCollection {
fn add(&mut self, v: i8) {}
fn get_all(&self) -> &Vec<i8> {
&vec![1, 2, 3]
}
}
是否可以,例如,写类似 impl Collection<&dyn Stringable> for StaticCollection
的东西,以便 StaticCollection
可以存储在通用 Collection<&dyn Stringable>
变量中?
这取决于StaticCollection
如何实现,但技术上是可行的:
impl<'a> Collection<&'a dyn Stringable> for StaticCollection {
fn add(&mut self, v: &'a dyn Stringable) {
}
fn get_all(&self) -> &Vec<&'a dyn Stringable> {
panic!()
}
}
但是 StaticCollection
必须使用 &dyn Stringable
项创建。
例如 (Link to playground):
fn main() {
let mut vs: &mut Collection<&dyn Stringable> = &mut StaticCollection {
v: vec![&0,&1,&2]
};
for v in vs.get_all() {
println!("{}", v.string());
}
}
struct StaticCollection {
v: Vec<&'static dyn Stringable>,
}
impl<'a> Collection<&'a dyn Stringable> for StaticCollection {
fn add(&mut self, v: &'a dyn Stringable) {
}
fn get_all(&self) -> &Vec<&'a dyn Stringable> {
&self.v
}
}
请注意,我们在 'a
生命周期内是通用的,这是针对 Vec
的 项 ,但是因为特征(如定义的那样) 需要 get_all
到 return 从 self
借来的 &Vec
,不可能“改造” Vec
。所以如果你定义了StaticCollection { v: Vec<&i8> }
(或者Vec<i8>
,get_all
就无法实现(不“泄露”一个新的Vec
,这可能不是你想要的)。
get_all
的完整生命周期实际上是:
fn get_all<'s>(&'s self) -> &'s Vec<&'a ...>
一句警告:dyn Trait
可能会让您在使用编译器和借用检查器时陷入困境。
您可能还想查看 this blog post 探索类似概念的“类型族”。