amo*_*fis 1 scala implicit shapeless
标题可能很模糊,但这是代码: https: //github.com/amorfis/why-no-implicit
所以有一个工具可以转化Map[String, Any]为简单的案例类。测试通过了,这段代码说明了它的全部内容:
case class TargetData(
groupId: String,
validForAnalysis: Boolean,
applicationId: Int
)
val map = Map(
"groupId" -> "123456712345",
"applicationId" -> 31,
"validForAnalysis" -> true
)
val transformed: TargetData = MapDecoder.to[TargetData](map).transform
Run Code Online (Sandbox Code Playgroud)
这段代码有效。当提供简单的情况时,它很好地创建了案例类实例map
但是,该transform方法必须在“外部”调用 - 就像示例中一样。当我尝试将其移至该MapDecoder.to方法时 - 编译器抱怨缺少隐式。
所以我将代码更改MapDecoder.to为:
def to[A](map: Map[String, Any]) = new MapDecoderH[A](map)
Run Code Online (Sandbox Code Playgroud)
对此:
def to[A](map: Map[String, Any]) = new MapDecoderH[A](map).transform
Run Code Online (Sandbox Code Playgroud)
它停止工作了。这是为什么?为什么在一种情况下提供了隐含的内容,而在另一种情况下则没有提供?所有的变化是我想transform在其他地方调用该方法以MapDecoder.to返回案例类而不是某个转换器。
更新:
to[A]如果我想在要转换的对象内实现方法怎么办?让我们称之为DataFrame,我希望这段代码能够工作:
val df: DataFrame = ...
df.to[TargetData] // There is no apply called here
Run Code Online (Sandbox Code Playgroud)
问题是在这种情况下没有什么可以传递给apply。用括号 ( ) 调用它也是不可行的,df.to[TargetData]()因为编译器需要在括号中隐含。是否可以不使用宏来解决它?
当编译器可以明确地在当前范围内找到具有匹配类型的值时,可以提供隐式。
外部def to编译器看到你想要的MapDecoder[TargetData]。
它所看到的MapDecoder[A]并没有理由相信A =:= TargetData。
在这种情况下,您必须将所有隐式作为to方法的参数传递。从你的代码看来它必须是类似的
def to[A, R <: HList](map: Map[String, Any])(implicit
gen: LabelledGeneric.Aux[A, R],
transformer: MapDecoder[R]
) = new MapDecoderH[A](map).transform
Run Code Online (Sandbox Code Playgroud)
但这会破坏人体工程学,因为你必须添加额外的参数,这些参数应该被推断,但不能 - 在 Scala 2 中,你要么显式传递所有类型参数,要么不传递任何类型参数。有多种方法可以解决这个问题,例如将类型参数应用程序拆分为 2 个调用,如下所示:
class Applier[A] {
def apply[R <: HList](map: Map[String, Any])(implicit
gen: LabelledGeneric.Aux[A, R],
transformer: MapDecoder[R]
) = new MapDecoderH[A](map).transform
}
def to[A] = new Applier[A]
Run Code Online (Sandbox Code Playgroud)
这将被用作
MapDecoder.to[A](map)
Run Code Online (Sandbox Code Playgroud)
由编译器脱糖为
MapDecoder.to[A].apply[InferredR](map)(/*implicit*/gen, /*implicit*/transformer)
Run Code Online (Sandbox Code Playgroud)
它会非常相似, MapDecoder.to[TargetData](map).transform但通过一个技巧,它看起来会更好。