简体   繁体   English

如何获得 rust 嵌套泛型

[英]How to get a rust nested generic

I'm trying to write a generic struct that will hold a collection and the sum of all the inserted values into that collection.我正在尝试编写一个通用结构,它将保存一个集合以及该集合中所有插入值的总和。

That is a generic type that keeps the sum of all added values to it.这是一个通用类型,它保留所有附加值的总和。

pub struct SummedCollection<T>
where 
    T::Item: std::ops::Add<Output=T::Item> + std::ops::Div<Output=T::Item>
{
    sum: T::Item,
    values: T,
}

impl<T> SummedCollection<T> { 
    pub fn new() -> Self{
        SummedCollection {
            sum: T::Item::default(),
            values: T::new(),
        }
    }
    pub fn push(&mut self, value: T::Item) {
        self.values.push(value);
        self.sum = self.sum + value;
    }
    pub fn sum(&self) -> T::Item {
        self.sum
    }
}

The intended use would be:预期用途是:

let v: SummedCollection<Vec<i32>> = SummedCollection::new();
v.push(5);
v.push(10);

I would then expect: v.sum() == 15 .然后我会期望: v.sum() == 15

I get an error "^^^^ associated type `Item` not found" on each assurance of T::Item, what do I need to do to access the nested generic (the i32 in my example)?我在每次保证 T::Item 时都收到错误“^^^^ 未找到关联类型‘Item’”,我需要做什么才能访问嵌套泛型(我的示例中的 i32)?

The compiler doesn't know T::Item .编译器不知道T::Item You intended T to be some collection type, but didn't tell it to the compiler, so it doesn't know that.您希望T成为某种集合类型,但没有告诉编译器,所以它不知道。

You have to tell the compiler T implements some collection trait.你必须告诉编译器T实现了一些集合特性。 A trait like that doesn't exist in the standard library, but you can easily write your own:标准库中不存在这样的特征,但您可以轻松编写自己的特征:

pub trait Collection {
    type Item;
    fn push(&mut self, value: Self::Item);
}

// Example implementation, you can implement the trait for any collection type you wish
impl<T> Collection for Vec<T> {
    type Item = T;
    fn push(&mut self, value: T) {
        self.push(value);
    }
}

pub struct SummedCollection<T: Collection> {
    sum: T::Item,
    values: T,
}

impl<T> SummedCollection<T>
where
    T: Collection + Default,
    T::Item: Default + Copy + std::ops::Add<Output = T::Item> + std::ops::Div<Output = T::Item>,
{
    pub fn new() -> Self {
        SummedCollection {
            sum: T::Item::default(),
            values: T::default(),
        }
    }
    pub fn add(&mut self, value: T::Item) {
        self.values.push(value);
        self.sum = self.sum + value;
    }
    pub fn sum(&self) -> T::Item {
        self.sum
    }
}

Note I made some additional changes:注意我做了一些额外的改变:

  • Required T::Item to be Copy and Default .要求T::ItemCopyDefault It may be possible to work around this need, but it's easy this way.可以解决此需求,但这种方式很容易。
  • Required T: Default and changed T::new() to T::default() , since we already have a default-constructible trait - no need to reinvent the wheel.必需的T: Default并将T::new()更改为T::default() ,因为我们已经具有可默认构造的特征 - 无需重新发明轮子。
  • Moved some of the bounds from the struct to the impl, since it is better this way .将一些边界从结构移到 impl,因为这样更好

Edit: Thanks for @mcarton that pointed out that we can use Extend for that:编辑:感谢@mcarton 指出我们可以为此使用Extend

#[derive(Debug)]
pub struct SummedCollection<Collection, T> {
    sum: T,
    values: Collection,
}

impl<Collection, T> SummedCollection<Collection, T>
where
    Collection: Extend<T> + Default,
    T: Default + Copy + std::ops::Add<Output = T> + std::ops::Div<Output = T>,
{
    pub fn new() -> Self {
        SummedCollection {
            sum: T::default(),
            values: Collection::default(),
        }
    }
    pub fn add(&mut self, value: T) {
        self.values.extend(std::iter::once(value));
        self.sum = self.sum + value;
    }
    pub fn sum(&self) -> T {
        self.sum
    }
}

But note that because it requires an additional generic parameter it will affect users: instead of但请注意,因为它需要一个额外的通用参数,所以它会影响用户:而不是

let v: SummedCollection<Vec<i32>> = SummedCollection::new();

You'll have to write你必须写

let v: SummedCollection<Vec<i32>, _> = SummedCollection::new();

Or explicitly, of course:或者明确地,当然:

let v: SummedCollection<Vec<i32>, i32> = SummedCollection::new();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM