Scala隐式解析疑问:为何外部可调用transform内部却缺失隐式?
问题1:MapDecoder.to方法内部调用transform时的隐式缺失问题
原因分析
你的MapDecoderH类的transform方法应该依赖某个隐式参数(比如Decoder[A])。原代码中:
def to[A](map: Map[String, Any]) = new MapDecoderH[A](map)
返回的是MapDecoderH[A]实例,之后调用.transform时,编译器会在调用transform的代码位置查找所需的隐式参数(比如Decoder[TargetData]),此时上下文里的隐式实例是可用的,因此编译通过。
但修改后的to方法直接调用transform:
def to[A](map: Map[String, Any]) = new MapDecoderH[A](map).transform
此时transform的隐式参数需要在to方法的内部作用域解析,但to方法的签名没有声明需要这个隐式参数,编译器无法自动传入,因此报错缺失隐式。
解决方法
把隐式参数暴露到to方法的签名中,让编译器在调用to时解析隐式:
// 假设transform需要的隐式是Decoder[A] def to[A](map: Map[String, Any])(implicit decoder: Decoder[A]): A = new MapDecoderH[A](map).transform
这样调用MapDecoder.to[TargetData](map)时,编译器会自动查找并传入Decoder[TargetData]实例,编译就能通过。
问题2:DataFrame实现无括号调用的to[A]方法(不使用宏)
实现思路
利用Scala的扩展方法和仅含隐式参数列表的方法语法:Scala允许方法只定义隐式参数列表,此时调用可以省略括号。
具体代码
- 定义DataFrame的扩展类,添加
to[A]方法:
import org.apache.spark.sql.DataFrame import org.apache.spark.sql.Encoder implicit class DataFrameToCaseClassOps(df: DataFrame) { // 方法仅含隐式参数列表,支持无括号调用 def to[A](implicit encoder: Encoder[A]): Seq[A] = df.as[A].collect().toSeq }
- 调用方式(无括号):
val df: DataFrame = ... val result: Seq[TargetData] = df.to[TargetData]
说明
- 这里依赖Spark的
Encoder[A]隐式实例(针对case class,Spark会自动生成),如果是自定义转换逻辑,可以替换隐式参数为你自己的转换类型,比如implicit converter: DataFrame => Seq[A]。 - 只要方法的参数部分只有隐式参数列表,Scala就允许无括号调用,完全不需要宏来实现。
内容的提问来源于stack exchange,提问作者amorfis
相关产品推荐
相关产品推荐

