簡體   English   中英

如何獲得 rust 嵌套泛型

[英]How to get a rust nested generic

我正在嘗試編寫一個通用結構,它將保存一個集合以及該集合中所有插入值的總和。

這是一個通用類型,它保留所有附加值的總和。

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
    }
}

預期用途是:

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

然后我會期望: v.sum() == 15

我在每次保證 T::Item 時都收到錯誤“^^^^ 未找到關聯類型‘Item’”,我需要做什么才能訪問嵌套泛型(我的示例中的 i32)?

編譯器不知道T::Item 您希望T成為某種集合類型,但沒有告訴編譯器,所以它不知道。

你必須告訴編譯器T實現了一些集合特性。 標准庫中不存在這樣的特征,但您可以輕松編寫自己的特征:

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
    }
}

注意我做了一些額外的改變:

  • 要求T::ItemCopyDefault 可以解決此需求,但這種方式很容易。
  • 必需的T: Default並將T::new()更改為T::default() ,因為我們已經具有可默認構造的特征 - 無需重新發明輪子。
  • 將一些邊界從結構移到 impl,因為這樣更好

編輯:感謝@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
    }
}

但請注意,因為它需要一個額外的通用參數,所以它會影響用戶:而不是

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

你必須寫

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

或者明確地,當然:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM