如何使用Shapeless从对象中获取类型为Option[T]的字段值
错误原因
- 你将字段对应的
Witness定义为方法外的顶层变量,它的路径依赖类型w.T无法在方法的隐式参数列表里被编译器正确解析,无法关联到传入的case class对应字段 - 隐式参数中
Selector.Aux的返回类型硬写为Option[T3]的写法没有和泛型参数做正确绑定,编译器无法推导T3的实际类型
修复方案
两种实现方式均可以规避编译错误,同时满足你指定Selector#apply返回值类型为Option[T]的需求:
方案1:固定提取author字段的专用实现
import shapeless._ import shapeless.ops.record._ case class Author(name: String) case class Book(title: String, author: Option[Author]) val book = Book("Types and Programming Languages", Option(Author("Benjamin Pierce"))) def getAuthor[T, L <: HList](book: T)( implicit gen: LabelledGeneric.Aux[T, L], sel: Selector.Aux[L, Witness.`'author`.T, Option[Author]] ): Option[Author] = { val opt = sel(gen.to(book)) opt.foreach { author => // 你需要的自定义逻辑写在这里 println(s"拿到作者信息:${author.name}") } opt } // 调用测试 val author = getAuthor(book) println(author) // 输出:Some(Author(Benjamin Pierce))
方案2:支持提取任意Option字段的通用实现
如果需要复用逻辑提取不同case class的不同Option类型字段,可以使用更泛化的实现:
import shapeless._ import shapeless.ops.record._ case class Author(name: String) case class Book(title: String, author: Option[Author]) val book = Book("Types and Programming Languages", Option(Author("Benjamin Pierce"))) def getOptionField[K, T, L <: HList, V](t: T, witness: Witness.Aux[K])( implicit gen: LabelledGeneric.Aux[T, L], sel: Selector.Aux[L, K, Option[V]] ): Option[V] = { val opt = sel(gen.to(t)) opt.foreach { value => // 通用自定义逻辑写在这里 } opt } // 调用时传入对应字段的Witness即可 val author = getOptionField(book, Witness('author)) println(author) // 输出:Some(Author(Benjamin Pierce)) // 如果尝试提取非Option类型字段会直接编译报错,符合类型安全要求 // val title = getOptionField(book, Witness('title)) // 编译失败
内容的提问来源于stack exchange,提问作者yoshiki
相关产品推荐
相关产品推荐

