简体   繁体   English

Scala:访问有界泛型类型的“静态”成员

[英]Scala: access “static” member of bounded generic type

I want to achieve the following: 我要实现以下目标:

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

Is something like this possible in Scala? 这样在Scala中可能吗? This fails because the value of T is not found in Tester.test . 这将失败,因为在Tester.test找不到T的值。

typeSpecific is not a static member, it belongs to instances of SubA and SubB , which you don't have. typeSpecific不是静态成员,它属于SubASubB实例,而您没有这些实例。 You also can't statically access anything from a type parameter (it's a type, not an object). 您也不能从类型参数(它是类型,而不是对象)中静态访问任何内容。

This won't work as is, because you don't have instances of SubA and SubB , nor can you obtain them via new Tester[SubA] . 这将无法正常工作,因为您没有SubASubB实例,也无法通过new Tester[SubA]获得它们。 But you can require that Tester mixes in a type of Super in order to make it one (and thus have typeSpecific ). 但是您可以要求Tester混合使用Super类型,以使其成为Super类型(并因此具有typeSpecific )。 This would require you change Super , SubA , and SubB to traits, and would also make your instance anonymous classes. 这将需要您将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

You could also require A <: Super as a constructor parameter for Tester , which is probably the cleaner option. 您还可能需要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

Any way you cut it, you're going to need an instance of SubA or SubB . 以任何方式削减它,都将需要SubASubB的实例。

You're going to have to use reflection combined with typeTags to get your desired result. 您将必须结合使用反射和typeTags来获得所需的结果。 I warn you, it's somewhat ugly: 我警告你,这有点丑陋:

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
}

I also feel I should mention that typeSpecific is not static as it is part of a class, in scala static members are defined in objects/companion objects only. 我还觉得应该提到typeSpecific不是静态的,因为它是类的一部分,在scala中,静态成员仅在对象/伴侣对象中定义。 Using objects it would be cleaner to do something like this: 使用对象可以更干净地执行以下操作:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM