gpt4 book ai didi

scala - 从案例类中提取给定类型的值

转载 作者:行者123 更新时间:2023-12-02 13:46:04 26 4
gpt4 key购买 nike

是否可以使用 Shapeless 从案例类中提取特定类型的值?到目前为止,我可以这样做:

def fromCaseClass[T, R <: HList](value: T)(implicit ga: Generic.Aux[T, R]): R = {
ga.to(value)
}

这允许我以程序方式提取值:

scala> case class ServiceConfig(host: String, port: Int, secure: Boolean)
defined class ServiceConfig

scala> val instance = ServiceConfig("host", 80, true)
instance: ServiceConfig = ServiceConfig(host,80,true)

scala> fromCaseClass(instance).select[Boolean]
res10: Boolean = true

scala> fromCaseClass(instance).select[Int]
res11: Int = 80

但是,当我尝试编写一个函数来执行此操作时,我遇到了找不到隐式函数的问题:

def getByType[C, X](value: C)(implicit ga: Generic.Aux[C, X]): X = {
fromCaseClass(value).select[X]
}

<console>:12: error: could not find implicit value for parameter ga: shapeless.Generic.Aux[C,R]
fromCaseClass(value).select[X]

大概我得到这个是因为编译器无法验证我的参数不是案例类。我有办法做到这一点吗?

我对 Shapeless 还很陌生,所以我不完全确定我是在尝试做一些疯狂的事情还是错过了一些简单的事情。

更新

我觉得我离目标又近了一步。我可以这样实现:

def newGetByType[C, H <: HList, R]
(value: C)
(implicit ga: Generic.Aux[C, H], selector: Selector[H, R]): R = {
ga.to(value).select[R]
}

这允许我从案例类中进行选择:

scala> val s: String = newGetByType(instance)
s: String = host

但这似乎只适用于案例类中的第一种类型:

scala> val i: Int = newGetByType(instance)
<console>:17: error: type mismatch;
found : String
required: Int
val i: Int = newGetByType(instance)

我走在正确的道路上吗?

最佳答案

你已经很接近了......

您的 newGetByType 的主要问题是它没有给您任何方法来显式指定您希望提取的类型(并且,正如您所观察到的,在LHS 不足以进行推断)。

为什么不能明确指定要提取的类型?再次定义一下,

def getByType[S, C, L <: HList](value: C)
(implicit gen: Generic.Aux[C, L], sel: Selector[L, S]): S =
gen.to(value).select[S]

理想情况下,我们希望能够指定类型参数 S,允许从 value 参数推断出 C,并且L 通过 C 的隐式解析进行计算。然而不幸的是,Scala 不允许我们部分指定类型参数……要么全有,要么全无。

因此,使其发挥作用的技巧是将类型参数列表分为两部分:一个可以完全显式指定,另一个可以完全推断:这是一种通用技术,而不是特定于 shapeless 的技术。

我们通过将计算的主要部分移动到辅助类来实现这一点,该辅助类由我们要显式提供的类型参数化,

class GetByType[S] {
def apply[C, L <: HList](value: C)
(implicit gen: Generic.Aux[C, L], sel: Selector[L, S]): S =
gen.to(value).select[S]
}

请注意,这里我们现在可以假设 S 是已知的,并且 apply 的两个类型参数都可以推断出来。我们完成了 getByType 现在的简单定义,它只是提供了一个可以放置显式类型参数的位置,并实例化辅助类,

def getByType[S] = new GetByType[S]

这会给你你想要的结果,

scala> import shapeless._, ops.hlist._
import ops.hlist._

scala> :paste
// Entering paste mode (ctrl-D to finish)

class GetByType[S] {
def apply[C, L <: HList](value: C)
(implicit gen: Generic.Aux[C, L], sel: Selector[L, S]): S =
gen.to(value).select[S]
}

// Exiting paste mode, now interpreting.

defined class GetByType

scala> def getByType[S] = new GetByType[S]
getByType: [S]=> GetByType[S]

scala> case class ServiceConfig(host: String, port: Int, secure: Boolean)
defined class ServiceConfig

scala> val instance = ServiceConfig("host", 80, true)
instance: ServiceConfig = ServiceConfig(host,80,true)

scala> getByType[String](instance)
res0: String = host

scala> getByType[Int](instance)
res1: Int = 80

scala> getByType[Boolean](instance)
res2: Boolean = true

关于scala - 从案例类中提取给定类型的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26951669/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com