2017-04-27 3 views
2

のは、私は、以下の特性のScalaの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の方法をご覧ください。警告はありませんでした。)

良い方法はありますか?あなたが試みることができる一つのことは、オブジェクトを検索するnameを使用してMap[String,Animal]を作成するためにそれを使用し、その後、Animalを拡張するタイプのセットを取得するためにリフレクションを使用することです(ない標準のScalaツールセット、サードパーティ製の1とした場合?)

+0

藤堂、自分の質問に答えます。 2つの投稿に基づく解決策を見つけました: 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.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) 
関連する問題