2017-04-27 13 views
2

이의 내가 이제 다음과 같은 특성스칼라 ADT를 -

trait Named { 
    def name: String 
} 

다음과 같은 대수 데이터 형식

sealed trait Animal extends Named 

case object Dog extends Animal { 
    override val name: String = "dog man" 
} 

case object Cat extends Animal { 
    override val name: String = "cat man" 
} 

case object Owl extends Animal { 
    override val name: String = "I am an owl left in the dark" 
} 

있다고 가정 해 봅시다 일반적인 방식으로 문자열에서 역 직렬화 할 수있는 방법이있다, 다음 방법으로 문자열의 인스턴스를 내 동물 ADT로 역 직렬화 할 수 있습니다.

가 지속 된 값에서 쉽게 인스턴스화 할 수 없습니다

object Animal { 

    def apply(name: String): Animal = name match { 
    case Dog.name => Dog 
    case Cat.name => Cat 
    } 
} 

@oxbow_lakes 그의 answer 그 말에 언급하고있다.이 또한 해당하지만 거대한 열거 형의 경우를 제외하고는 (예 : 모든 통화) 큰 오버 헤드가 발생하지 않습니다.

나는 새 값을 추가 할 때 명시 적으로 발생하기 쉬운 오류로 직렬화 코드에 추가 할 필요가 있다는 사실 (내가 컴파일러 인 - 완전한 일치의 저를 경고하지만,이 걸릴 것이라고 생각 것을 발견 위의 Owlapply 방법을 참조하십시오. 경고가 발행되지 않았습니다 ...)

더 좋은 방법이 있습니까? 당신이 시도 할 수

+0

몽땅, 내 자신의 질문에 대답. 두 개의 게시물을 기반으로 한 해결책을 찾았습니다. http://stackoverflow.com/questions/25838411/cant-prove-that-singleton-types-are-singleton-types-while-generating-type-class 및 http : // /stackoverflow.com/questions/43650265/implicit-arguments-how-to-encode-in-function-signature 다음과 같이 요약됩니다. http://stackoverflow.com/a/43658710/101715 – Yaneeve

답변

3

한 가지 Animal을 확장 유형의 집합을 얻기 위해 반사를 사용하는 것입니다 (이 아닌 경우 표준 스칼라 도구 세트, 타사 하나?), 다음 오브젝트를 조회 할 name를 사용하여 Map[String,Animal]을 만들 것을 사용 값을 입력 한 다음 Animal.apply 함수에서지도를 사용하십시오.

Animal 서브 클래스를 얻는 방법에 대한 자세한 내용은 this question을 참조하십시오.

+0

작동하지만 좋아할 것입니다. 가능하다면 반사없이 그렇게하는 방법 – Yaneeve

+0

호기심에서 벗어나 반사를 피하는 것이 좋을까요? 'String'을'Animal' 맵으로 설정하는 데 한 번만 사용해야하므로 성능에 영향을 미치지 않으며'Animal' 하위 클래스를 놓치지 않습니다. –

+0

분명히 정확성과 효율성에 관한 귀하의 평가가 정확합니다. 나는 컴파일 시간 해결책으로 더 나아질 것이라는 이유는 그것을 할 방법이 있어야한다고 생각한다는 것입니다. '봉인 된 형질 (sealed traits) '은 런타임 확장이 없으므로 모든 알려진 직접 하위 유형이 미리 알려짐을 컴파일러에게 알려줍니다. 나는이 지식을 활용할 수 있어야한다고 생각한다. 나는 그것을하는 법을 모른다. 그래서 나는 그 질문을 게시했다. 내가 원하는 바가 엉성한 매크로 또는 매크로로 수행 될 수 있는지 궁금합니다.IMHO, 일반적으로 컴파일 시간에 수행 할 수있는 작업은 – Yaneeve

4

이미 enumeratum 라이브러리에 의해 해결이 문제 : https://github.com/lloydmeta/enumeratum

귀하의 코드를 다음과 같이 작성할 수 있습니다 : 나를 위해

import enumeratum._ 
import enumeratum.EnumEntry.Lowercase 

sealed trait Animal extends EnumEntry with Lowercase 
object Animal extends Enum[Animal] { 
    val values = findValues 

    case object Dog extends Animal 
    case object Cat extends Animal 
    case object Owl extends Animal 
} 

val dogName = Animal.Dog.entryName 
val dog = Animal.withNameInsensitive(dogName)