2015-04-03 2 views
1

Я использую шаблон «case class вместо enumeration» и хочу иметь список всех значений для «перечисления», а также несколько методов. Поэтому я решил не просто выводить классы классов из закрытого абстрактного класса, а выводить все запечатанные абстрактные классы из суперкласса под названием 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, все они, кажется, требуют наличия экземпляра класса, присутствующего, и я не мог " t заставить их работать с параметризованным признаком 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

Так из ваших комментариев в «то, что я хотел бы иметь» раздел, похоже, что вы хотите в дальнейшем параметризировать на «экземпляр Т». Вы можете добавить абстрактный метод к LookupTrait, который должен был реализовать подклассы; у него могла бы быть подпись:

def instantiateElement(name: String): T 

Я немного смущен тем, что вы пытаетесь сделать. Scala Enumerations предназначены для использования как Java-перечисления - для обработки фиксированного конечного набора вариантов. Обычно вы привязываете каждый из этих элементов к имени PascalCase, чтобы позднее можно было сопоставить неизвестное значение с этим набором имен. Ваш случай выглядит не так, как фиксированный конечный набор и более похожий на динамический открытый набор. Может быть, вам это совсем не нужно; может быть, просто Set[String].

1

У меня есть LIB, что делает что-то близкое, только вы должны определить случай объектов, а не только с использованием строк: https://github.com/lloydmeta/enumeratum

Он питается от макроса, который, с небольшим количеством работы/модификации, могли бы привести к точно, что вы хотите (во время компиляции, определить экземпляры на основе строк)

Смежные вопросы