我有以下代码:
test("test $") {
val spark = SparkSession.builder().enableHiveSupport().master("local").appName("$").getOrCreate()
import spark.implicits._
val df = Seq(("A", 1), ("B", 2), ("C", 3)).toDF("name", "age")
df.select($"name").show()
spark.stop()
}
$
中的$"name"
在隐式类中定义:
implicit class StringToColumn(val sc: StringContext) {
def $(args: Any*): ColumnName = {
new ColumnName(sc.s(args: _*))
}
}
使用此隐式类,为类StringContext定义$ method
以便以下代码是正确的:
val x = StringContext("Hello")
x.$("World")
我会问隐式转换在df.select($"name").show()
答案 0 :(得分:1)
StringContext
是Scala标准库的类:This class provides the basic mechanism to do String Interpolation
,类似于
val name = "Jennie"
val statement = s"Her name is $name" // s actually is a method of StringContext that is used to insert its arguments between corresponding parts of the string context`
隐式课程StringToColumn
是将$
方法简化为StringContext
课程。
implicit class StringToColumn(val sc: StringContext) {
def $(args: Any*): ColumnName = {
new ColumnName(sc.s(args: _*)) // call s method
}
}
假设select
需要column
类型的参数。调用select($"column_string")
,scala编译器不会立即放弃,它会查找StringContext
到column
之间的隐式转换,并找出StringToColumn
。
更新s("Her name is $name")
错误的原因。因为当scala编译器看到s"Her name is $name"
它将重写为StringContext("Her name is ", "").s(name)
时。如果您使用s("...")
,编译器会将s
视为String Interpolation
的函数而不是指标。
您可以通过创建像test.scala
class A{
val name = "Jennie"
val a = s"Her name is $name"
}
然后使用scalac -print test.scala
,它会在重写阶段后显示代码。
package <empty> {
class A extends Object {
private[this] val name: String = _;
<stable> <accessor> def name(): String = A.this.name;
private[this] val a: String = _;
<stable> <accessor> def a(): String = A.this.a;
def <init>(): A = {
A.super.<init>();
A.this.name = "Jennie";
A.this.a = new StringContext(scala.Predef.wrapRefArray(Array[String]{"Her name is ", ""}.$asInstanceOf[Array[Object]]())).s(scala.Predef.genericWrapArray(Array[Object]{A.this.name()}));
()
}
}
}