如何在编译时使用 shapeless 获取 case class 字段的名称作为 string/symbol?
How to get the name of a case class field as a string/symbol at compile time using shapeless?
我想在编译时以某种方式获取 val 中案例 class 的字段名称(可能是单例类型的字符串或符号?)。
类似于以下内容:
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
?)。我想要一些东西,我可以在不单独指定的情况下获取 case class 字段的名称。这样,如果我重构 class 中的 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"
编辑:好的,我查看了 gabriele 的问题,通过使用 Keys
我能够获得包含记录的(标记的)键的 HList。
我需要的是获取一个特定字段,而不是包含所有字段的列表。
我正在尝试使用 select
获取特定密钥,但到目前为止我还没有成功
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)
好的,多亏了 Travis 的评论,我才开始工作:
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))
>>
的参数是一个 Witness
,它将成员名称捕获为编译时符号。当你写 >> 'bar
时,符号文字被隐式转换为 Witness
,这通常是你想要的,但你也可以自己提供一个:
scala> case class Foo(bar: String, baz: Boolean)
defined class Foo
scala> val barKey = shapeless.Witness('bar)
barKey: shapeless.Witness.Aux[shapeless.tag.@@[Symbol,String("bar")]] = ...
scala> shapeless.lens[Foo] >> barKey
res0: shapeless.Lens[Foo,String] = shapeless.Lens$$anon@344bfb60
正如我在上面的评论中提到的,您可能还对位置选择器感兴趣:
scala> shapeless.lens[Foo] >> shapeless.nat._1
res1: shapeless.Lens[Foo,Boolean] = shapeless.Lens$$anon@16e9d434
甚至只是:
scala> shapeless.lens[Foo] >> 1
res2: shapeless.Lens[Foo,Boolean] = shapeless.Lens$$anon@4be29007
这些不需要您在代码中的任何位置写入成员名称,但如果您重新排列成员,您 运行 会遇到麻烦。
我想在编译时以某种方式获取 val 中案例 class 的字段名称(可能是单例类型的字符串或符号?)。
类似于以下内容:
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
?)。我想要一些东西,我可以在不单独指定的情况下获取 case class 字段的名称。这样,如果我重构 class 中的 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"
编辑:好的,我查看了 gabriele 的问题,通过使用 Keys
我能够获得包含记录的(标记的)键的 HList。
我需要的是获取一个特定字段,而不是包含所有字段的列表。
我正在尝试使用 select
获取特定密钥,但到目前为止我还没有成功
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)
好的,多亏了 Travis 的评论,我才开始工作:
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))
>>
的参数是一个 Witness
,它将成员名称捕获为编译时符号。当你写 >> 'bar
时,符号文字被隐式转换为 Witness
,这通常是你想要的,但你也可以自己提供一个:
scala> case class Foo(bar: String, baz: Boolean)
defined class Foo
scala> val barKey = shapeless.Witness('bar)
barKey: shapeless.Witness.Aux[shapeless.tag.@@[Symbol,String("bar")]] = ...
scala> shapeless.lens[Foo] >> barKey
res0: shapeless.Lens[Foo,String] = shapeless.Lens$$anon@344bfb60
正如我在上面的评论中提到的,您可能还对位置选择器感兴趣:
scala> shapeless.lens[Foo] >> shapeless.nat._1
res1: shapeless.Lens[Foo,Boolean] = shapeless.Lens$$anon@16e9d434
甚至只是:
scala> shapeless.lens[Foo] >> 1
res2: shapeless.Lens[Foo,Boolean] = shapeless.Lens$$anon@4be29007
这些不需要您在代码中的任何位置写入成员名称,但如果您重新排列成员,您 运行 会遇到麻烦。