我已经挣扎了几天,试图创建一个宏或使用shapeless创建一个方法/函数来提取字段名称和值作为元组[String,String]。
让我们想象一下下面的案例类:
case class Person(name: String, age: Int)
我想要这样的东西(实际上不需要是case类中的方法(。
case class Person(name: String, age: Int) {
def fields: List[(String, String)] = ???
}
// or
def fields[T](caseClass: T): List[(String, String)] = ???
我在这里看到了很多类似的解决方案,但我无法使它与我的(String,String(用例一起工作
我也很感激一些文献来学习和扩展我对宏的知识,我有《Scala编程》(Martin第三版(和《Scala程序设计》(O'REILLY-Dean Wampler&Alex Payne(,只有O'REILLY有一个关于宏的很小的章节,老实说,它非常缺乏。
谢谢!
PD:我使用的是Scala 2.12.12,所以对于case类productElementNames,我没有那些花哨的新方法,比如:(
基于LabelledGeneric
和Keys
类型类
import shapeless.LabelledGeneric
import shapeless.HList
import shapeless.ops.hlist.ToTraversable
import shapeless.ops.record.Keys
case class Person(name: String, age: Int)
def fields[P <: Product, L <: HList, R <: HList](a: P)(
implicit
gen: LabelledGeneric.Aux[P, L],
keys: Keys.Aux[L, R],
ts: ToTraversable.Aux[R, List, Symbol]
): List[(String, String)] = {
val fieldNames = keys().toList.map(_.name)
val values = a.productIterator.toList.map(_.toString)
fieldNames zip values
}
fields(Person("Jean-Luc, Picard", 70))
// : List[(String, String)] = List((name,Jean-Luc, Picard), (age,70))
scastie
IDEA。。。显示错误。。。无隐式自变量
IntelliJ在编辑器中的错误突出显示有时在涉及类型级别代码和宏时不是100%准确。最好将其视为指导,并适当信任Scala编译器,所以如果编译器很满意,但IJ不满意,那么就使用编译器。另一种选择是尝试Scala Metals,它应该在编译器诊断和编辑器内错误突出显示之间有一对一的映射。
为什么使用LabelledGeneric。辅助,按键。Aux,ToTraversable。辅助
这是使用一种称为类型类的设计模式。我的建议是阅读《无定形类型宇航员指南》,特别是关于链接相关函数的部分
依赖类型函数提供了一种计算一种类型的方法来自另一个。我们可以链接依赖类型的函数来执行涉及多个步骤的计算。
考虑以下类型之间的依赖关系
input type
|
gen: LabelledGeneric.Aux[P, L],
|
output type
input type
|
keys: Keys.Aux[L, R]
|
output type
注意例如LabelledGeneric
的输出类型L
如何变成Keys
的输入类型。通过这种方式,您向编译器显示了类型之间的关系,作为回报,编译器能够在程序运行之前为您提供一个HList
,表示来自Product
的字段名,表示特定事例类。
需要ToTraversable
,这样您就可以从启用以下位的HList
中获得常规ScalaList
.toList.map(_.name)
希望这至少能给你一点方向。要搜索的一些关键字有:类型类、依赖类型、隐式解析、类型别名Aux-pattern、类型成员与类型参数、类型精化等。类型级别社区有一个新的Discord频道,您可以在这里获得进一步的指导。