您正在尝试做的事情称为结构类型,它受 Scala 支持。因为没有实际的类,JVM 上的实现必须依赖反射,所以getC与基于 trait 的解决方案相比,调用会非常慢。在这些情况下调用getC称为反射调用,编译器实际上会发出警告,除非您import scala.language.reflectiveCalls承认自己知道自己在做什么。
在我看来,有一个更优雅的解决方案,它依赖于通常称为类型类的东西。您将定义一个HasCtrait 来定义“拥有一个C”的含义,然后您将为 和 提供A 实现B。因为HasC是你的特质,即使你无法控制 and 的实现,你也可以A做到B。然后,您将定义具有隐式可用的readC任何类型。Scala 通过上下文边界支持这一点:. THasC[T]def readC[T: HasC]
这是一个工作示例:
class A {
def getCFromA: Int = 10
}
class B {
def getCFromB: Int = 100
}
trait HasC[T] {
def c(t: T): Int
}
object HasC {
implicit object AHasC extends HasC[A] {
def c(a: A): Int = a.getCFromA
}
implicit object BHasC extends HasC[B] {
def c(b: B): Int = b.getCFromB
}
}
def readC[T : HasC](t: T): Int = implicitly[HasC[T]].c(t)
val a = new A()
val b = new B()
readC(a)
readC(b)
这条线
def readC[T : HasC](t: T): Int = implicitly[HasC[T]].c(t)
只是一种(可以说)更好的写作方式
def readC[T](t: T)(implicit hasC: HasC[T]): Int = hasC.c(t)
请注意,这是更通用的,因为我从不需要getC同时定义Aand B,这就是我将方法重命名为getCFromAand的原因getCFromB。
类型类是 Scala 中许多函数式编程的基础,类似的概念在其他现代语言中可用,例如 Haskell、Rust(特征)或 Swift(协议)。