假设我们有两个方法签名
def drive[U <: Vehicle](c : U) = ???
def drive(c : Vehicle) = ???
Run Code Online (Sandbox Code Playgroud)
这些定义之间有什么区别?第二个是第一个的简写还是它们根本不同?它们在概念上是不同的还是只是 scala 语言对它们的处理不同?
考虑Miles用来在概念上区分两种多态性的术语
方法
def drive(c: Vehicle)
Run Code Online (Sandbox Code Playgroud)
既是参数单态的,因为它没有类型参数,又是子类型的多态,因为它可以接受 aLada和Tesla.
现在在这种特殊情况下,这两种方法受到同等约束
def drive[U <: Vehicle](c : U) = ???
def drive(c : Vehicle) = ???
Run Code Online (Sandbox Code Playgroud)
然而轻微的修改揭示了一些差异
scala> sealed trait Vehicle
| case object Škoda extends Vehicle
| case object Tesla extends Vehicle
trait Vehicle
object Škoda
object Tesla
scala> def f(a: Vehicle, b: Vehicle) = a
def f(a: Vehicle, b: Vehicle): Vehicle
scala> f(Škoda, Tesla)
val res21: Vehicle = Škoda
scala> def f[A <: Vehicle](a: A, b: A) = a
def f[A <: Vehicle](a: A, b: A): A
scala> f(Škoda, Tesla)
val res22: Product with Vehicle with java.io.Serializable = Škoda
Run Code Online (Sandbox Code Playgroud)
请注意我们如何使用参数多态性激活推理和统一,以便编译器为车辆参数推导出更精确的类型。
一般来说,参数多态方法允许我们向编译器提出更多要求,并通过类型类对其类型参数施加进一步的编译时约束
trait FixableByHittingIt[A]
implicit val fixLadaByHittingIt = new FixableByHittingIt[Lada.type] {}
def drive[U <: Vehicle](c : U)(implicit ev: FixableByHittingIt[U]) = ???
drive(Lada) // ok
drive(Tesla) // nope, needs sci-fi mechanic
Run Code Online (Sandbox Code Playgroud)
作为个人方面的说明,IMO 类型参数是通往丰富有趣的 Scala 类型检查器世界的门户。一旦您开始将类型检查器视为另一种可以像许多其他机器一样编程的机器,您每天都会成功地进行编程,类型级别的神秘表达式就会变得不那么令人生畏,因为您意识到您已经拥有了所有需要的心理工具要进行编程,它们只需要应用于恰好在程序生命周期中的不同时间运行的不同机器。因此,您的两种方法之间有趣的区别在于,参数化多态方法是一种入门药物:)