基于方法定义泛型类型(结构类型)



我正在尝试根据某些函数声明一个类型类。

class A{
def getC = 10
}
class B {
def getC = 100
def getB = 9
}

def readC[T <: {def getC():Int}](obj:T) = {
obj.getC()
}
val a = new A()
val b  = new B()
readC(a)
readC(b) 

我希望 readC 应该同时适用于 A 和 B.我也无法对 A 和 B 类进行更改,因此基于特征的解决方案在这里不起作用。

另外,有没有更好的方法?

你尝试做的事情称为结构类型,它由 Scala 支持。因为没有实际的类,所以JVM上的实现必须依赖于反射,因此与基于trait的解决方案相比,调用getC将非常慢。在这些情况下调用getC称为反射调用,编译器实际上会发出警告,除非您import scala.language.reflectiveCalls确认您知道自己在做什么。

在我看来,有一个更优雅的解决方案依赖于通常称为类型类的东西。您将定义一个HasC特征,该特征定义了"拥有C"的含义,然后您将为AB提供实现。因为HasC是你的特质,所以即使无法控制AB的实现,你也可以做到这一点。然后,您将定义readC采用隐式可用的任何类型THasC[T]。Scala 通过上下文边界支持这一点: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)

请注意,这要通用得多,因为我从不要求在AB上定义getC,这就是为什么我将方法重命名为getCFromAgetCFromB

Typeclasses 是 Scala 中许多函数式编程的基础,类似的概念在其他现代语言中也可用,例如 Haskell、Rust(traits)或 Swift(协议)。

问题是

def getC = 100

与 函数签名不同

def getC() = 100

AB在没有()的情况下getC,因此您需要从类型约束中删除()

def readC[T <: {def getC: Int}](obj: T) = {
obj.getC
}

更好的方法是使用类型类。在线查看有关如何执行此操作的许多好教程。

相关内容

  • 没有找到相关文章