如何制作一个可以实例化类的参数化特征?
问题描述:
我正在使用“案例类而不是枚举”模式,并且想要列出每个“枚举”的所有值以及一些方法。所以我决定不仅仅从一个密封的抽象类派生我的案例类,而是从一个叫做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")
}
我宁愿只是在每个查询的同伴对象定义字符串列表,并有特质实例的情况下类。但是,当我在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"
)
}
答
从您的意见
所以,你的“我想有什么”一节,它看起来像你想的“实例T”进一步参数。你可以添加一个抽象方法到LookupTrait
,子类将需要实现;它可能有这样的签名:
def instantiateElement(name: String): T
虽然我对你想要做什么感到困惑。 Scala枚举意味着像Java枚举一样使用 - 用于处理一组固定的,有限的选择。您通常将每个元素绑定到一个PascalCase名称,以便您以后可以对这组名称匹配未知值。你的情况看起来不像固定的有限集合,更像是一个动态的开放集合。也许你根本不需要这些;也许一个普通的Set[String]
就足够了。
答
我有一个lib,做一些接近,只是你需要定义的情况下对象,而不是仅仅使用字符串:https://github.com/lloydmeta/enumeratum
它由是,随着一点点的工作/修改,可能可能导致宏动力正是你想要的(在编译时,基于字符串定义实例)