如何制作一个可以实例化类的参数化特征?

时间:2015-04-03 13:08:47

标签: scala generics reflection

我正在使用" case类而不是Enumeration"模式,并希望得到每个"枚举"的所有值的列表以及一些方法。因此,我决定不仅从密封的抽象类派生我的case类,而是从名为Lookup的超类派生所有密封的抽象类,并定义一个LookupTrait,从中派生抽象类'伴侣物体。

abstract class Lookup {
  val name: String
  override def toString = name
}

trait LookupTrait[T<:Lookup] {
  val all: Map[String, T]
  val default: T
  def withName(name: String): T = 
    if(all.contains(name)) all(name)
    else default   
}

示例查找如下所示:

sealed case class StudyGoal(override val name: String)  extends Lookup 

object StudyGoal extends LookupTrait[StudyGoal] {

  override val all = Map(
      "present new evaluation method" -> StudyGoal("present new evaluation method"), 
      "evaluate existing product" -> StudyGoal("evaluate existing product"),
      "develop new theoretical model" -> StudyGoal("develop new theoretical model"), 
      "unknown" -> StudyGoal("unknown")
      ) 
   override val default = StudyGoal("unknown")
}

我更愿意在每个查找的伴随对象中定义一个字符串列表,并让trait实例化case类。但是当我在Scala中发现三种不同的反射方式时 - 使用Manifest,TypeTag,并获得类in the documentation所描述的类的构造函数,所有这些方法似乎都需要有一个类的实例存在,我无法让它们在参数化的LookupTrait特性中工作。

我希望有类似的东西:

abstract class Lookup {
  val name: String
  override def toString = name
}

trait LookupTrait[T<:Lookup] {
  val allNames: List[String] 

  val default: T = //Instantiate a T using the string "unknown". 
  //It is OK that this string will be the same for all Lookups. 

  val all: Map[String, T] = allNames.map(
    n => n -> //instantiate a T here, using n as the parameter
) += default 

  def withName(name: String): T = 
    if(all.contains(name)) all(name)
    else default   
}

sealed case class StudyGoal(override val name: String)  extends Lookup 

object StudyGoal extends LookupTrait[StudyGoal] {

  override val allNames = List(
      "present new evaluation method"), 
      "evaluate existing product",
      "develop new theoretical model"
      ) 
}

2 个答案:

答案 0 :(得分:1)

我有一个关闭的lib,只需要你定义case对象而不是只使用字符串:https://github.com/lloydmeta/enumeratum

它由一个宏驱动,通过一点工作/修改,可能会产生你想要的(在编译时,基于字符串定义实例)

答案 1 :(得分:0)

因此,根据您对“我想要的内容”部分的评论,看起来您希望进一步参数化“实例化T”。您可以向LookupTrait添加一个抽象方法,该子类需要实现;它可能有一个签名,如:

def instantiateElement(name: String): T
但是,我对你要做的事情感到有些困惑。 Scala Enumerations旨在像Java枚举一样使用 - 用于处理固定的,有限的选择集。您通常将每个元素绑定到PascalCase名称,以便稍后可以将未知值与这组名称进行模式匹配。您的案例看起来不像固定的有限集,更像是动态的开集。也许你完全不需要这些;也许普通Set[String]就足够了。