< 返回版块

eric642 发表于 2021-12-21 22:42

地址: https://kaisery.github.io/trpl-zh-cn/ch19-03-advanced-traits.html 如下是书中的原话: 这类似于泛型。那么为什么 Iterator trait 不像示例 19-13 那样定义呢?

pub trait Iterator<T> {
    fn next(&mut self) -> Option<T>;
}

示例 19-13: 一个使用泛型的 Iterator trait 假想定义

区别在于当如示例 19-13 那样使用泛型时,则不得不在每一个实现中标注类型。这是因为我们也可以实现为 Iterator for Counter,或任何其他类型,这样就可以有多个 Counter 的 Iterator 的实现。换句话说,当 trait 有泛型参数时,可以多次实现这个 trait,每次需改变泛型参数的具体类型。接着当使用 Counter 的 next 方法时,必须提供类型注解来表明希望使用 Iterator 的哪一个实现。 通过关联类型,则无需标注类型,因为不能多次实现这个 trait。对于示例 19-12 使用关联类型的定义,我们只能选择一次 Item 会是什么类型,因为只能有一个 impl Iterator for Counter。当调用 Counter 的 next 时不必每次指定我们需要 u32 值的迭代器。 ---------原话结束--------

我感觉这段解释不太对吧, 我impl Itertator for Counter实现也不用多次实现啊. 我觉得使用关联类型最大的好处避免了在trait中使用泛型, 可以作为一个trait对象使用.

评论区

写评论
作者 eric642 2021-12-22 09:37

这么一想, 如果结构体用的泛型, 那么即使使用关联类型, 其实都还是可以有很多实现的. 不过这种情况下确实可以不必在调用函数的时候指定类型

--
👇
Grobycn: 要是在追加如下一种实现

struct CantCopy;

impl<T> Iterator<CantCopy> for Foo<T>
where
    T: Copy,
{
    fn next(&mut self) -> Option<CantCopy> {
        Some(CantCopy)
    }
}

那么以下代码会有不明确的类型

let mut foo = Foo::new(1i32);
for x in foo {
    // x 的类型是 i32 还是 CantCopy
}
Grobycn 2021-12-22 00:26

要是在追加如下一种实现

struct CantCopy;

impl<T> Iterator<CantCopy> for Foo<T>
where
    T: Copy,
{
    fn next(&mut self) -> Option<CantCopy> {
        Some(CantCopy)
    }
}

那么以下代码会有不明确的类型

let mut foo = Foo::new(1i32);
for x in foo {
    // x 的类型是 i32 还是 CantCopy
}
作者 eric642 2021-12-21 23:38

如果是这样定义的Foo去实现Iterator, 那么只需要new的时候指定下类型就好了.

trait Iterator<T> {
    fn next(&mut self) -> Option<T>;
}
struct Foo<T>
where
    T: Copy,
{
    a: T,
}

impl<T> Foo<T>
where
    T: Copy,
{
    fn new(a: T) -> Foo<T> {
        return Foo { a: a };
    }
}

impl<T> Iterator<T> for Foo<T>
where
    T: Copy,
{
    fn next(&mut self) -> Option<T> {
        return Some(self.a);
    }
}

--
👇
Grobycn: 原文意思是,假如定义成

trait Iterator<T> {
    fn next(&mut self) -> Option<T>;
}

对于一个类型 Foo,你可以 impl Iterator<String> for Fooimpl Iterator<Vec<u8>> for Foo 以及其它无穷种实现。

当你调用 Foo::next 的时候,你需要指定泛型参数 Foo::next::<Vec<u8>>(&mut foo)

但是使用关联类型,避免了这种麻烦。

Grobycn 2021-12-21 23:12

原文意思是,假如定义成

trait Iterator<T> {
    fn next(&mut self) -> Option<T>;
}

对于一个类型 Foo,你可以 impl Iterator<String> for Fooimpl Iterator<Vec<u8>> for Foo 以及其它无穷种实现。

当你调用 Foo::next 的时候,你需要指定泛型参数 Foo::next::<Vec<u8>>(&mut foo)

但是使用关联类型,避免了这种麻烦。

作者 eric642 2021-12-21 22:46

在官方的slice的标准库中, 也是使用了泛型去实现的Iterator的, 那么用泛型定义trait并没有什么问题, 最大的原因是使用泛型无法使用trait对象:

impl< 'a,T>Iterator for Iter< 'a,T>{
  type Item =  & 'a T;
  #[inline]
  fn next(&mut self) -> Option<& 'a T>{
    unsafe {
      assume(!self.ptr.as_ptr().is_null());
      if mem::size_of::<T>()!=0 {
        assume(!self.end.is_null());
        
      }if self.ptr.as_ptr()as *const T==self.end {
        None
      }else {
        Some(&mut*self.post_inc_start(1))
      }
    }
  }
作者 eric642 2021-12-21 22:44

impl<T> Itertator for Counter<T>这样实现trait

1 共 6 条评论, 1 页