Scala:访问"静态"有界泛型的成员

时间:2015-05-06 16:37:01

标签: scala abstract-class abstract-type bounded-types

我想实现以下目标:

abstract class Super {
  def typeSpecific: Int
}

class SubA extends Super {
  def typeSpecific = 1
}
class SubB extends Super {
  def typeSpecific = 2
}

class Tester[T <: Super] {
  def test = T.typeSpecific
}

val testerA = new Tester[SubA]
val testerB = new Tester[SubB]

testerA.test // should return 1
testerB.test // should return 2

在Scala中是否可以这样?此操作失败,因为在T中找不到Tester.test的值。

2 个答案:

答案 0 :(得分:1)

typeSpecific不是静态成员,它属于SubASubB的实例,您没有。您也无法静态访问类型参数中的任何内容(它是类型,而不是对象)。

这不会按原样运行,因为您没有SubASubB的实例,也无法通过new Tester[SubA]获取它们。但是,您可以要求Tester混合Super类型以使其成为一个(因此具有typeSpecific)。这需要您将SuperSubASubB更改为特征,并且还会使您的实例成为匿名类。

trait Super {
  def typeSpecific: Int
}

trait SubA extends Super {
  def typeSpecific = 1
}
trait SubB extends Super {
  def typeSpecific = 2
}

// The self-type `this: A =>` requires the mix-in.
class Tester[A <: Super] { this: A =>
  def test = typeSpecific
}

val testerA = new Tester[SubA] with SubA
val testerB = new Tester[SubB] with SubB

scala> testerA.test
res2: Int = 1

scala> testerB.test
res3: Int = 2

您还可以要求A <: Super作为Tester的构造函数参数,这可能是更清晰的选项。

abstract class Super {
  def typeSpecific: Int
}

class SubA extends Super {
  def typeSpecific = 1
}
class SubB extends Super {
  def typeSpecific = 2
}

class Tester[A <: Super](s: A) {
  def test = s.typeSpecific
}

val testerA = new Tester(new SubA)
val testerB = new Tester(new SubB)

scala> testerA.test
res5: Int = 1

scala> testerB.test
res6: Int = 2

如果你削减它,你将需要一个SubASubB的实例。

答案 1 :(得分:0)

您必须使用反射结合typeTags来获得所需的结果。我警告你,这有点难看:

import scala.reflect.runtime.universe._

abstract class SuperClass {
  def typeSpecific: Int
}

class SubA extends SuperClass {
  def typeSpecific = 1
}
class SubB extends SuperClass {
  def typeSpecific = 2
}

class Tester[T <: SuperClass: TypeTag] {
  def test = typeTag[T].mirror.runtimeClass(typeOf[T]).newInstance.asInstanceOf[T].typeSpecific
}

我还觉得我应该提到typeSpecific不是静态的,因为它是类的一部分,在scala静态成员只在对象/伴随对象中定义。使用对象,做这样的事情会更干净:

trait SuperTrait {
  def typeSpecific: Int
}

object SubA extends SuperTrait {
  def typeSpecific = 1
}
object SubB extends SuperTrait {
  def typeSpecific = 2
}

class Tester(testObject : SuperTrait) {
  def test = testObject.typeSpecific
}

new Tester(SubA).test
new Tester(SubB).test