[英]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::Item
為Copy
和Default
。 可以解決此需求,但這種方式很容易。T: Default
並將T::new()
更改為T::default()
,因為我們已經具有可默認構造的特征 - 無需重新發明輪子。 編輯:感謝@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.