2015-04-03 50 views
1

我正在使用“案例类而不是枚举”模式,并且想要列出每个“枚举”的所有值以及一些方法。所以我决定不仅仅从一个密封的抽象类派生我的案例类,而是从一个叫做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" 
    ) 
} 

回答

0
从您的意见

所以,你的“我想有什么”一节,它看起来像你想的“实例T”进一步参数。你可以添加一个抽象方法到LookupTrait,子类将需要实现;它可能有这样的签名:

def instantiateElement(name: String): T 

虽然我对你想要做什么感到困惑。 Scala枚举意味着像Java枚举一样使用 - 用于处理一组固定的,有限的选择。您通常将每个元素绑定到一个PascalCase名称,以便您以后可以对这组名称匹配未知值。你的情况看起来不像固定的有限集合,更像是一个动态的开放集合。也许你根本不需要这些;也许一个普通的Set[String]就足够了。

1

我有一个lib,做一些接近,只是你需要定义的情况下对象,而不是仅仅使用字符串:https://github.com/lloydmeta/enumeratum

它由是,随着一点点的工作/修改,可能可能导致宏动力正是你想要的(在编译时,基于字符串定义实例)