Skip to content

Latest commit

 

History

History
76 lines (55 loc) · 2.5 KB

abstract_type_member.adoc

File metadata and controls

76 lines (55 loc) · 2.5 KB

Abstract Type Member

让我们进一步深入使用 Type Aliases,这样的用法称为 Abstract Type Members。

有了 Abstract Type Members,我们可以做到"定义一个抽象类型,并希望其他人告诉我具体类型 - 我们可以用 MyType 来引用这个类型"。 Abstract Type Members 最基础的功能是允许我们无需使用 class Clazz[A, B] 构建泛型类(模板), 我们可以在类中命名 abstract type member(s),例如:

trait SimplestContainer {
  type A      // Abstract Type Member

  def value: A
}

对于熟悉 Java 的人来说,上面的语法看起来与 Container<A> 类似, 但我们会在 Path Dependent Types 和下面的例子中看到 Abstract Type Members 功能更强大。

需要注意的是尽管 type A 的注释中包含 "abstract",但是它与抽象字段不同 - 所以即使我们不"实现"类型成员 A,也可以创建一个 SimplestContainer 实例:

new SimplestContainer // 合法,但是 A 是 "anything"

你可能想知道 A 是什么类型,考虑到我们没有提供任何关于它的信息。事实上,type Atype A >: Nothing <: Any 的简写,意味着 A 可以是"任意类型(anything)"。

object IntContainer extends SimplestContainer {
  type A = Int

  def value = 42
}

因为我们使用 Type Alias 提供了一个抽象类型,现在我们可以实现一个返回 Int 的方法。

当我们对 Abstract Type Members 应用类型约束时,事情变得更有趣了。 比如,想象你想要定义一个只能存储任意 Number 实例的容器。 我们可以在定义 type members 加上这样的约束:

trait OnlyNumbersContainer {
  type A <: Number
  def value: A
}

或者我们可以稍后在类层次结构中添加约束,例如通过混入声明 "only Numbers" 的特质:

trait SimpleContainer {
  type A
  def value: A
}

trait OnlyNumbers {
  type A <: Number
}

val ints = new SimpleContainer with OnlyNumbers {
  type A = Integer
  def value = 12
}

// 下面的定义不能通过编译
val _ = new SimpleContainer with OnlyNumbers {
  def value = "" // error: type mismatch; found: String(""); required: this.A
}

正如你所看到的,我们可以像使用 Type Parameters 一样使用 Abstract Type Members, 但是我们无需忍受显式四处传递类型的痛苦 - 因为类型是个字段,我们需要传递。 我们需要付出的代价就是按名称绑定这些类型。