我想用一个对象类型参数化一个类,以使我的代码更通用。通过这样做,我不需要为扩展某个特征的所有对象实现。
我有以下代码来演示我的目标:
abstract trait Foo {
def greet
}
object Coo extends Foo {
def greet = println("Coo!")
}
object Boo extends Foo {
def greet = println("Boo!")
}
class A[Fooer <: Foo] {
def moo = asInstanceOf[Fooer].greet()
}
object Main extends App {
new A[Coo.type].moo() // hopefully prints "Coo!"
}
代码抛出异常:
java.lang.ClassCastException: A cannot be cast to Foo
我相信这是因为asInstanceOf
调用似乎隐含地使用this
。
基本上我的问题是:如何通过参数化在类中获取对象的实例?
答案 0 :(得分:4)
我相信这是因为
asInstanceOf
调用似乎隐含地使用了this
。
Scala中的每个类都扩展了Any
,它继承了特殊方法asInstanceOf
等等。我不会说它发生隐式地 - 它只是你正在调用该类的成员方法,而该类正在调用它。与您撰写def moo = greet
相同。
此外,只要您使用asInstanceOf
,就会要求编译器撒谎并继续前进。这通常会导致ClassCastException
。在这种情况下,它是因为您尝试将实例A
强制转换为Foo
的某个未知子类型。这永远不会奏效。在特定情况下,您尝试将单件类型Coo.type
传递给A
的实例,然后创建Coo.type
的新实例。虽然还有许多其他原因导致其无法正常工作,但其中一个原因是您无法创建单例类型的第二个实例 - 因为某种原因,它被称之为。
更一般地说,你不知道你可以简单地构造给定类型的对象。类型没有构造函数,类具有。
这可能是一个简化示例的副作用,但您关注的是使用某个类型参数创建A
的实例,而无需将其传递给实际对象,但是您需要对象#39;关注已经存在。那么为什么不通过它们呢?
class A[Fooer <: Foo](f: Fooer) {
def moo = f.greet
}
唯一的另一种方法是提供可以构建Fooer
的证据。但是,没有 type 约束来证明某些东西是可构造的类。您可以做的是改为使用Class
元对象:
class A[Fooer <: Foo](clazz: Class[Fooer]) {
def moo = clazz.newInstance.greet
}
然而,这是粗糙的。首先,它不适用于上面的单例类型(因为它们不能再次构建)。第二,我们只能在没有提供构造函数参数的情况下调用newInstance
,并且无法强制执行。
所以虽然这会奏效:
scala> class Bar extends Foo { def greet = print("Bar") }
scala> new A(classOf[Bar]).moo
Bar
以下不会:
scala> class Baz(i: Int) extends Foo { def greet = println("Baz") }
defined class Baz
scala> new A(classOf[Baz]).moo
java.lang.InstantiationException: Baz
scala> new A(classOf[Coo.type]).moo
<console>:14: error: class type required but Coo.type found
new A(classOf[Coo.type]).moo
^
或者,您可以使用允许您一致地构建Foo
实例的类型类,但这需要为每个子类创建一个。 e.g:
trait FooBuilder[A] {
def build(): A
}
implicit object BarBuilder extends FooBuilder[Bar] {
def build() = new Bar
}
class A[Fooer <: Foo](implicit fb: FooBuilder[Fooer]) {
def moo = fb.build().greet
}