2016-03-15 15 views
9

私は何とかコンパイル時に、caseクラスのフィールドの名前をval(おそらくシングルトン型の文字列かシンボルか)で取得したいと考えています。次のようなケースレットフィールドの名前を文字列/シンボルとして取得するには、シェイプレスを使用してコンパイル時に?

何か:

import shapeless._ 
case class MyClass(field1: String, field2: Int) 
val field1Lens = lens[MyClass] >> 'field1 
// val name = field1Lens.name // it should be "field1", aka 'field1.name 

私は必ずしもレンズを使用する必要はありません、働く任意の技術は、(LabelledGenericで何か?)大丈夫です。私は別にそれを指定することなく、ケースクラスフィールドの名前を得ることができるものを持っていたいと思います。このようにして、クラス内のfield1メンバーの名前をリファクタリングすると、それに応じてnameが変更されます。

マクロはコンパイル時にシンボルの名前を知らないので、次は動作しませんもちろん

val name = 'field1 
val field1Lens = lens[MyClass] >> name // can't possibly work 

は私がlens[MyClass] >> name.narrowを試してみましたが、それは

このいずれかを動作しません。私は現在やっているし、もちろん、私はそれを好きではない:

// If I change the name of the field, compilation fails 
// and I'm forced to check this line of code so I can change the string in the line below 
protected val fieldNameCheck = lens[X].someField 
val someField = "someField" 

編集:[OK]を、私はgabrieleの質問を見た、と0を使用して、レコードの(タグ付き)キーを含むHListを取得できます。 私が必要とするのは、特定のフィールドを1つだけ取得することです。すべてのフィールドを含むリストではありません。

私は特定のキーを取得するためにselectを使用しようとしているが、私は、[OK]をこれまでのところ、私はそれが働いてしまったトラヴィスのコメントのおかげ

import shapeless._ 
import shapeless.syntax.singleton._ 
import shapeless.ops.record._ 

case class Foo(bar: String, baz: Boolean) 
val labl = LabelledGeneric[Foo] 
val keys = Keys[labl.Repr].apply 

// the following doesn't work 
// val bar = 'bar.narrow 
// keys.select[bar.type] 
// keys.get('bar) 
+0

[LabelledGenericインスタンスからのラベル値の抽出]の可能な複製(http://stackoverflow.com/questions/27434302/extract-label-values-from-a-labelledgeneric-instance) –

+0

私は理解しているとは思わない動機づけ - それはあなたが別の場所にそれを書く必要がないように、あなたのコードの1つの場所にリテラル '' bar 'を書きたいと思うように聞こえ、リファクタリングでどのように役立つか分かりません。メンバ名の変更が心配な場合は、位置セレクタを使用する方が良いでしょう。 –

+0

短いストーリー:シリアライズライブラリ。私はカスタム・シリアライザを書く必要がありません。ライブラリーが何をしているか(フィールド名をキーとして使用してjsonオブジェクトを作成するなど)、フィールドの名前を別の場所に置く必要があるからです弾性サーチ上)。私はリテラル 'バーを一度書くだけですが、ケースクラスが変更されてもコードはコンパイルされます。私が必要とする各 '' bar'には、全く同じ名前の '(bar:T)' caseクラスのパラメータがあることを確認するためにたくさんのテストが必要です。 –

答えて

6

>>への引数は、メンバー名をコンパイル時のシンボルとして取得するWitnessです。あなたは>> 'bar書くとき、リテラル記号が暗黙的に何をしたい通常である、Witnessに変換されていますが、自分でものを提供することができます:

私は上記のコメントで言及したよう
scala> case class Foo(bar: String, baz: Boolean) 
defined class Foo 

scala> val barKey = shapeless.Witness('bar) 
barKey: shapeless.Witness.Aux[[email protected]@[Symbol,String("bar")]] = ... 

scala> shapeless.lens[Foo] >> barKey 
res0: shapeless.Lens[Foo,String] = [email protected] 

、あなたも興味がある可能性があり

scala> shapeless.lens[Foo] >> shapeless.nat._1 
res1: shapeless.Lens[Foo,Boolean] = [email protected] 

あるいは単に:位置セレクタに

scala> shapeless.lens[Foo] >> 1 
res2: shapeless.Lens[Foo,Boolean] = [email protected] 

これらは、メンバーNAを書くためにあなたを必要としません私はあなたのコードのどこにでもいますが、メンバーを再配置すると問題に陥ります。

+0

私は最終的に私が望むことをする2行の方法を作成しました。 –

+1

これは、私がやっていることのために非常に役立ちました。ありがとう! –

3

を成功していない:

import shapeless._ 
case class MyClass(field1: String, field2: Int) 

def fieldName[A](fieldKey: Witness.Lt[_ <: Symbol])(implicit mkl: MkFieldLens[A, fieldKey.T]) = { 
    lens[A] >> fieldKey 
    fieldKey.value.name 
} 

println(fieldName[MyClass]('field1)) 
+0

私はあなたが 'レンズ[A] >> fieldKey'なしでそれが割り当てられていないのでできると思います。 'MkFieldLens'インスタンスを解決するコンパイラは、フィールドがクラス上にあることを確認するのに十分です。 –

関連する問題