Scala 中有没有办法调用属于某个类型的方法?例如,假设我有一个叫做 trait 的特性Constructable,它描述了类型,而不是可以构造它们自己的默认实例。然后,我可以编写以下代码:
trait Constructable[A] {
def construct: A
}
class Foo(x: Int) extends Constructable[Foo] {
def construct = new Foo(0)
}
def main(args: Array[String]) {
val f = new Foo(4)
println(f.construct)
}
Run Code Online (Sandbox Code Playgroud)
这没问题,但我真正想要的是能够构造一个仅给定对象类型的默认对象。例如,假设我想接受一个可构造的列表并在列表的开头添加一个默认对象:
def prependDefault1[A <: Constructable[A]](c: List[A]): List[A] = {
val h = c.head
h.construct :: c
}
Run Code Online (Sandbox Code Playgroud)
上面的代码有效,但前提是 c 不为空。我真正想要的是写如下内容:
def prependDefault2[A <: Constructable[A]](c: List[A]): List[A] = {
A.construct :: c
}
Run Code Online (Sandbox Code Playgroud)
有没有办法实现这一点,可能是通过更改 a 的定义,Constructable使该construct方法属于“类”而不是“实例”(使用 Java 术语)?
你不能这样做,但你可以使用类型类来做到这一点:
trait Constructable[A] {
def construct: A
}
// 'case' just so it's printed nicely
case class Foo(x: Int)
// implicit vals have to be inside some object; omitting it here for clarity
implicit val fooConstructable = new Constructable[Foo] {
def construct = new Foo (0)
}
def prependDefault2[A : Constructable](c: List[A]): List[A] = {
implicitly[Constructable[A]].construct :: c
}
Run Code Online (Sandbox Code Playgroud)
进而:
scala> prependDefault2(Nil: List[Foo])
res7: List[Foo] = List(Foo(0))
Run Code Online (Sandbox Code Playgroud)
一些最后的评论:
隐式必须存在于对象内部。它可以位于三个位置:
object Constructable { implicit val fooConstructable = ... (类型类特征的伴随对象)
object Foo { implicit val fooConstructable = ... (我们为其实现类型类的类的伴随对象)
object SomethingElse { implicit val fooConstructable = ... (一些随机的无关对象)
只有在最后一种情况下您才需要使用import SomethingElse._,以便能够使用隐式。