提问人:Max888 提问时间:9/9/2023 最后编辑:kmdrekoMax888 更新时间:9/21/2023 访问量:48
对具有相同特征的特征对象进行 impl trait with move 方法
impl trait with move method for trait object of same trait
问:
我正在尝试在具有相同特征的盒装特征对象上实现特征。我以前做过这样的任务,其方法采用哪些工作正常,但不是.&self
self
// The purpose of this trait is to allow for converting any kind of "group" which might eg be nested tuples like below, and convert it into a flat Vec of Items
trait Group {
fn into_vec(self) -> Vec<Box<dyn Item>>;
}
trait Item: Group {}
// Foo is an Item an can also be made into a group
struct Foo {}
impl Item for Foo {}
impl Group for Foo {
fn into_vec(self) -> Vec<Box<dyn Item>> {
vec![Box::new(self)]
}
}
// impl Group for data structures which contain items or other nested structures containing items
impl<A: Group, B: Group> Group for (A, B) {
fn into_vec(self) -> Vec<Box<dyn Item>> {
let mut new_vec = Vec::new();
new_vec.extend(self.0.into_vec().into_iter());
new_vec.extend(self.1.into_vec().into_iter());
new_vec
}
}
// Can create a single group fine
fn get_group() -> impl Group {
(Foo {}, (Foo {}, Foo {}))
}
// Sometimes I might want to return different groups from different braches so need to box them
// However I'm not sure how to implement this. self.into_vec() is an ifinite recursion, and can't deref self either.
impl Group for Box<dyn Group> {
fn into_vec(self) -> Vec<Box<dyn Item>> {
(*self).into_vec()
}
}
fn get_group_conditonal(condition: bool) -> impl Group {
if condition {
Box::new((Foo {}, (Foo {}, Foo {}))) as Box<dyn Group>
} else {
Box::new(Foo {}) as Box<dyn Group>
}
}
我意识到在这个特定示例中,我可以更改函数以返回以解决问题。但是,API 的其余部分具有将输入作为 .如果我不能,那么这将带入 API 的其余部分,并要求所有函数仅将盒装特征对象作为输入,而不是 ,如果可能的话,我想避免这种情况。fn get_*()
Box<dyn Group>
impl Group
impl Group for Box<dyn Group>
impl Group
答:
4赞
cafce25
9/9/2023
#1
我能想到的唯一解决方案,也是通常推荐的解决方案,是采用特征方法而不是:Box<Self>
Self
trait Group {
fn into_vec(self: Box<Self>) -> Vec<Box<dyn Item>>;
}
然后
impl Group for Box<dyn Group> {
fn into_vec(self: Box<Self>) -> Vec<Box<dyn Item>> {
(*self).into_vec()
}
}
正如您在 Playground 上看到的那样工作,因为它不必处理原始dyn Group
评论
0赞
Max888
9/9/2023
谢谢。我已经实现了这一点。这显然意味着我调用 .into_vec() 的任何地方我都需要对接收器进行装箱(如果还没有的话),但我猜没有办法解决这个问题,并且仍然比不能和不得不对任何地方的特征对象进行分组要好得多。impl Group for Box<dyn Group>
Box
3赞
Chayim Friedman
9/10/2023
#2
如果您不想为每次通话支付装箱费用,您可以有两种方法:
// The purpose of this trait is to allow for converting any kind of "group" which might eg be nested tuples like below, and convert it into a flat Vec of Items
trait Group {
fn into_vec(self) -> Vec<Box<dyn Item>>;
fn into_vec_dyn(self: Box<Self>) -> Vec<Box<dyn Item>>;
}
trait Item: Group {}
// Foo is an Item an can also be made into a group
struct Foo {}
impl Item for Foo {}
impl Group for Foo {
fn into_vec(self) -> Vec<Box<dyn Item>> {
vec![Box::new(self)]
}
fn into_vec_dyn(self: Box<Self>) -> Vec<Box<dyn Item>> {
self.into_vec()
}
}
// impl Group for data structures which contain items or other nested structures containing items
impl<A: Group, B: Group> Group for (A, B) {
fn into_vec(self) -> Vec<Box<dyn Item>> {
let mut new_vec = Vec::new();
new_vec.extend(self.0.into_vec().into_iter());
new_vec.extend(self.1.into_vec().into_iter());
new_vec
}
fn into_vec_dyn(self: Box<Self>) -> Vec<Box<dyn Item>> {
self.into_vec()
}
}
// Can create a single group fine
fn get_group() -> impl Group {
(Foo {}, (Foo {}, Foo {}))
}
// Sometimes I might want to return different groups from different braches so need to box them
// However I'm not sure how to implement this. self.into_vec() is an ifinite recursion, and can't deref self either.
impl Group for Box<dyn Group> {
fn into_vec(self) -> Vec<Box<dyn Item>> {
<dyn Group>::into_vec_dyn(self)
}
fn into_vec_dyn(self: Box<Self>) -> Vec<Box<dyn Item>> {
self.into_vec()
}
}
当然,为每个实现显式写出方法是......不太好,但我们可以通过拆分特征来解决这个问题:
trait GroupIntoVecDyn {
fn into_vec_dyn(self: Box<Self>) -> Vec<Box<dyn Item>>;
}
impl<T: Group> GroupIntoVecDyn for T {
fn into_vec_dyn(self: Box<Self>) -> Vec<Box<dyn Item>> {
self.into_vec()
}
}
// The purpose of this trait is to allow for converting any kind of "group" which might eg be nested tuples like below, and convert it into a flat Vec of Items
trait Group: GroupIntoVecDyn {
fn into_vec(self) -> Vec<Box<dyn Item>>;
}
因为是 的超级特征,你可以调用它的方法(甚至在 上),并且由于是一揽子实现,你实际上不必实现它。GroupIntoVecDyn
Group
dyn Group
评论
因为 extend
需要I: IntoIter<Item = T>
( 也有效。into_iter()
extend
new_vec.extend(self.0.into_vec())