Sparksql源码系列 | 读源码必须掌握的scala基础语法

2022-06-09 21:33:47 浏览数 (1)

这篇文章总结一下我在学习spark sql源码时,曾经纠结过的一些scala语法。

在精读sparksql源码之前,我们需要有一定的scala语法知识,来保证能够看懂sparksql代码,并上手调试。

有同学不会scala,就会有一种恐惧心理,其实不用怕,因为我一开始也不会scala代码。我是边看sparksql源码,边学习语法,看到不懂的地方,就从网上搜索相关的语法,把相关语法弄懂了之后,再写个scala的测试类,实现一个案例执行一下,加深理解,然后,再继续读源码。

到现在,我已经能熟练的用scala写一段了,虽然写不是很规范,但是看懂、调试、修改代码完全没有问题。 并且边用边学这种方式效率很高,这么说,并不是鼓励大家都用我这种方式,如果有条件,还是从网上找一些scala的基础视频看看,提前学一学,肯定会更好~

1、偏函数

当在调用一个函数时,把这个函数应用到参数中。如果传递所有预期的参数,则表示您已完全应用它。如果只传递几个参数并不是全部参数,那么将返回部分应用的函数。这样就可以方便地绑定一些参数,其余的参数可稍后填写补上。

代码语言:javascript复制
trait PartialFunction[-A,  B] extends (A => B) { self =>
  import PartialFunction._
  def isDefinedAt(x: A): Boolean
  
  def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] =
    new OrElse[A1, B1] (this, that)
 
  override def andThen[C](k: B => C): PartialFunction[A, C] =
    new AndThen[A, B, C] (this, k)

  def lift: A => Option[B] = new Lifted(this)

  def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
    if (isDefinedAt(x)) apply(x) else default(x)

  def runWith[U](action: B => U): A => Boolean = { x =>
    val z = applyOrElse(x, checkFallback[B])
    if (!fallbackOccurred(z)) { action(z); true } else false
  }
}

可以说,sparksql的源码中,到处都是偏函数。

比如:生成解析后逻辑执行计划中的解析器、优化逻辑执行计划的优化器等。

逻辑执行计划解析器ResolveRelations(解析表和视图):

逻辑执行计划优化器ColumnPruning(列剪裁):

2、嵌套函数

Scala允许定义函数内部的函数,而在其他函数中定义的函数称为局部函数。

sparksql源码中有太多这样的应用。

比如QueryPlan类中mapExpressions方法:

比如TreeNode类中legacyWithNewChildren方法:

3、柯里化函数

柯里化(Currying)函数是一个带有多个参数,并引入到一个函数链中的函数,每个函数都使用一个参数。

比如ParseDriver中的parse方法:

parse方法是个scala语法中的柯里化函数,它有两个输入参数,一个是查询语句,另外一个参数是方法参数。

toResult方法的实现是通过柯里化函数的参数传入的。

4、可变参数函数

Scala允许指定函数的最后一个参数可重复,这允许客户端将可变长度参数列表传递给函数。

5、case模式匹配

用的最多,解析规则、优化器中会经常用到

6、case类

case类在模式匹配中经常使用到,当一个类被定义成为case类后:

  • Scala会自动创建一个伴生对象并实现了apply方法,我们使用时不需要用new关键字就能创建该类对象。
  • 实现了unapply方法,可以通过模式匹配来获取类属性。
  • 实现了类构造参数的getter方法(构造参数默认被声明为val)
  • 实现了toString,equals,copy和hashCode等方法

为了方便模式匹配,LogicalPlan、SparkPlan都是case类

7、case类的copy()方法

copy()方法返回当前对象的复制,可以通过传递属性名 = 值的方式来自定义赋值出的对象的值

ColumnPruning(列裁剪)优化器,通过copy方法把子节点中不需要的列裁剪掉:

8、product类

TreeNode继承product类,通过Product类中的方法(productArity、productElement、productIterator)来操纵TreeNode实现类的参数

mapProductIterator:

9、scala隐式类

Scala中有个隐式转换系统,包括隐式参数 、隐式类、隐式对象等。

Scala中的隐式类是对类功能增强的一种形式。

比如AstBuilder导入ParserUtils,用到optionalMap方法:

而optionalMap方法是在ParserUtils中的EnhancedLogicalPlan隐式类里定义的:

10、foldLeft

在sparksql源码中第一次看到foldLeft语法时,理解了好长时间,才弄明白。

比如规则执行器RuleExecutor:

以上列了10种比较特殊的语法,还有一些,比如:

  • 列表(List)、集合(Set)、映射(Map)、选项(Option)、元组(Tuple)这些集合的基础用法
  • 类、对象、特质、继承等这些概念的理解

大家在学习scala时,重点关注一下就ok!

0 人点赞