泛型和相关类型之间有什么区别?

时间:2015-11-11 09:12:37

标签: rust

我的印象是这两件事只是在语义上不同。

然而,这是可能的:

struct Foo;

trait Bar<T> {
  fn resolve(&self) -> T;
}

impl Bar<isize> for Foo {
  fn resolve(&self) -> isize {
    return 0isize;
  }
}

impl Bar<usize> for Foo {
  fn resolve(&self) -> usize {
    return 1usize;
  }
}

#[test]
fn test_foo() {
  let foo = Foo;
  assert!((&foo as &Bar<isize>).resolve() == 0isize);
  assert!((&foo as &Bar<usize>).resolve() == 1usize);
}

虽然不是这样:

struct Foo;

trait Bar {
  type T;
  fn resolve(&self) -> Self::T;
}

impl Bar for Foo {
  type T = isize;
  fn resolve(&self) -> isize {
    return 0isize;
  }
}

impl Bar for Foo {
  type T = usize;
  fn resolve(&self) -> usize {
    return 1usize;
  }
}

#[test]
fn test_foo() {
  let foo = Foo;
  assert!((&foo as &Bar<T = isize>).resolve() == 0isize);
  assert!((&foo as &Bar<T = usize>).resolve() == 1isize);
}

它生成:

<anon>:8:1: 13:2 error: conflicting implementations for trait `Bar` [E0119]
<anon>: 8 impl Bar for Foo {
<anon>: 9   type T = isize;
<anon>:10   fn resolve(&self) -> isize {
<anon>:11     return 0isize;
<anon>:12   }
<anon>:13 }

我错过了什么吗?

我正在尝试实现的是什么特殊语法,还是在通用和相关类型之间存在真正的......技术......区别?

在某些情况下,相关类型与使用通用类型相比具有有形(而不是纯粹的代码漂亮)优势吗?

2 个答案:

答案 0 :(得分:5)

我将重复我的评论:类型参数和相关类型在语义上是不同的。然而,这是为什么它们都存在于语言中的要点 - 它们各自独立的工作,所以它不是“只是”语义差异,它是它们作为一个单独存在的全部原因来自类型参数的东西。

请注意,我甚至没有触及语法差异。当然,存在语法差异是绝对自然的。毕竟这些是独立的功能;如果他们有没有语法上的差异,那么你如何区分它们呢?它们的语法差异与语义差异紧密相关,因为定义相关类型的方式清楚地表明它们具有“输出”位置,与类型参数的“输入”位置相比,但在技术上它们都是类型参数和相关类型(以及顺便提一句,隐含的Self参数也是一样的。

答案 1 :(得分:0)

对于发现此问题的任何其他人,类型参数和相关类型之间也存在另一个技术区别。

如果您尝试使用关联类型实现特征,则可能会看到错误:

src/lib.rs:10:1: 15:2 error: the impl does not reference any types
defined in this crate; only traits defined in the current crate can
be implemented for arbitrary types [E0117]

如果您在箱子栏中导出了特征:

pub trait BarParam<TRtn> {
  fn bar() -> TRtn;
}

pub trait BarAssoc {
  type TRtn;
  fn bar() -> Self::TRtn;
}

你会发现导入这些特征的箱子只能实现:

impl<'a> BarParam<Foo> for &'a str {
  fn bar() -> Foo {
    return Foo;
  }
}

尝试实施时:

impl<'a> BarAssoc for &'a str {
  type TRtn = Foo;
  fn bar() -> Foo {
    return Foo;
  }
}

会导致上述错误。

坦率地说,我不确定这里发生了什么,所以如果你这样做,请务必添加评论或其他答案;但这是在你写箱子时避免相关类型的实际原因。