Scala简明语法

Posted NOSQL追随者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala简明语法相关的知识,希望对你有一定的参考价值。

    想看看SparkSQL的代码,发现跟中学看英文小说一样,只能模糊的猜测语言的含义,无法理解,更不要说欣赏。虽然一直对各种新的编程语言不太感冒,也不是很喜欢对一个基本概念反复包装然后还要定下规则,不过也没办法,还是得稍微了解下,否则这个代码怕看不下去。

    大概就是比较快速的把[1]里面的内容看一遍,基于C++理解一下,便于后面看代码,目标明确,内容简单,只是为了加深印象,避免看代码时候对着符号发呆:)

    

    Scala来自scalable,是面向对象和函数编程的混合体,静态类型,易扩展。Scala编译后的文件可以运行在JVM上,跟Java可以互操作。


  1. 有值和变量之分。值定义类似val x = 4 + 1, 一旦赋值不可改变,调用时候也不重新计算。变量定义类似var x = 1,可以重新赋值,支持lazy计算。类型会自动推导,也可以显式定义,val/var x : Int = 4 + 1。比起Int x = 4,这似乎更符合自然语言的风格

  2. Block跟C++里面一片代码类似,block最后一个表达式的值就是该block的返回结果,省掉了return,也避免了返回类型声明。Scala没有return关键字

  3. 函数function是表达式的集合(带参数的block),参数要指定类型,返回值类型自动推导。定义方式类似function(x : Int) => { x + 1 },也可以定义匿名函数。为了满足强迫症患者,有些间接的方法可以显式指定返回值类型,比如val x = new ((Int) => Int) { def apply(x : Int) =   {   x * 4  } } [3]。这里的=>可以理解为声明函数/方法时候的返回类型定义,而如果是定义函数/方法是参数后加冒号:

  4. 方法跟函数类似,不过方法可以很容易的指定返回类型,也可以有多个参数列表集合。def m(x : Int)(y : String) : Int = { ... }

  5. 类class跟C++类似,可以指定构造参数列表,返回Unit表示void,也可以写作(),通过new来创建。参数中x : Int = 5表示默认值,调用时候如果显式指定变量名则可以不遵守声明的变量顺序(一堆int参数的方法有救了)。成员默认public(不是很安全),可以添加private来限制,私有成员通过x_=()来实现getter/setter方法(写两个字母不好吗?)。通过类构造器参数里面声明val/var声明谁是成员变量,比如class Point(val x: Int = 0,  var y: Int = 0)表示类里面x,y是成员变量,但是x不能修改,y可以,也可以对y加上private[this] ,这样实例就不能外面调用,或者加上final,子类不可见,这对结构体来说太方便了,N行代码变一行。支持泛型,比如class X[A],可以在实例化或者继承时候指定A的具体类型。不能多继承。整体感觉类定义变简单了,很多成员变量的属性在参数里面就指定了

  6. case class是一类特殊的class,方便实现switch case,创建后一般就不变了,可以不用new关键词创建。case class比较值,不是引用,也许是调用变量的equal方法实现的。默认浅拷贝,可以显示调用copy深拷贝。标准用法x match { x => 't' \n _ => 'default' },下划线有点像占位符,在一些不需要参数的场景也是使用下划线。在C++里面为了可读性会为一些枚举定义ToString,使用case class会方便一些,比如ToString(enum) = val match { '1' => Bad }

  7. object是单例类,该类一旦定义好,该类的单例也就定义好了,比起C++里面的实现,节省了几行并发实例化的代码。do方法是保留方法

  8. trait是一个很好的特性,可以通过with关键字实现多继承(叫做mix-in),AOP(Aspect oriented programming)特性。函数式语言中一般有类似机制,大致等效于将对象上的函数摘除、重写或者添加一个新函数。traits通过extends实现继承(我纳闷咋不用符号了,Scala不是很喜欢符号吗?),通过override实现方法重载(比C++清晰),没有构造函数,从类继承时候也不必实现抽象方法。其和class的区别,这个哥们说的不错“Conceptually, a trait is a component of a class, not a class by itself. As such, it typically does not have constructors, and it is not meant to 'stand by itself'. I suggest using an abstract class when it has an independent meaning, and traits when you just want to add functionality in an object-oriented manner. " [4]

  9. scala 程序入口是Main。object Main {  def x(): Unit = println("Hello, Scala developer!") },通过Main.x()调用

  10. scala类型系统类似C++,Int/Char等是值,String等是对象,Any类型內建到语言层面,写代码应该会方便。类型关系见最后的图,来自[1]

  11. 继承或者组合:根据extends,with的顺序逐步初始化内部变量,就好像调用了每个class或者traits的Init方法一样

  12. 高阶函数:类似closure递归绑定,参数还可以是closure,可以是独立函数也可以是类实例的方法,支持泛型,指定或者推导均可

  13. currying, 如果一个方法有N个参数,调用时候参数M少于N,则自动形成一个函数,其参数列表就是剩下的N-M个参数,跟bind里面的占位符类似

  14. s"$var"可以自动拼接字符串,如果var是非字符,可以自动转换

  15. apply和unapply:apply类似从参数构造对象,unapply反过来,可以从对象得到参数,比如var Class(para) = new Class(para1), 则para是可以被解析为para1的,作用似乎不大,变量本身也可以访问,而且更清楚

  16. 关于variance 还是挺有用的,比如A <- B <- C继承关系,container[B] 表示只能放B,不能放A C,叫做invariance;container[+B] 表示能放C,不能放A, 叫variance;container[-B] 表示能放A,不能放C,这个比较诡异,似乎没啥用, 叫contrvariance

  17. 上面variance的约束只针对邻居,如果是有庞大的继承链,那么需要更灵活的约束,通过<: 和 >:可以控制继承链上的哪一段放进去。比如A <- B <- <- D <- E,container[P <: B] 则只能B的基类才能放进来, 比如append(A);container[P >: B] 则只能B的子类才能放进来,比如append(C)

  18. Inner class:跟C++不同,inner class默认只属于某个对象,而不是属于定义这个inner class的类。class A { class IA { def x(n : IA) { ... } } },默认情况下,x接受的类型必须属于某个对象,也只有这个对象创建的IA才能被接受;如果想越过这个规则,做类似C++ inner class的事情,则需要显式定义,class A { class IA { def x(n : A#IA) { ... } } }。给人的感觉是默认情况下IA是A对象形成后才存在的

  19. 函数参数可以是组合类型,即def cloneAndReset(obj : Cloneable with Resetable) : Cloneable = { ... },只有这么写才能约束参数类型。复杂一点的写法是先定义一个类型,在用这个类型作为参数

  20. Self-type:如果trait A里面引用了trait B,那么所有extends A的trait必须with B,在定义组合类行为时候可能更干净明确。这么做大概是因为trait之间约束比较弱,这种弱可能是故意的,从而为trait之间的自由组合打下基础

  21. By-Name parameter,与By-Value parameter相对,后者只evaluate一次,后面直接使用结果,而前者每次调用都要重新evaluate。写法类似def calculate(input: => Int) = input * 37,在类型前面加=>


    对于分布式系统来说,我觉得一个语言是否好用可能有两个方面比较重要,一个是并发模型,一个是异常体系。这一块Scala可以选择跟Java类似,比如线程池和try..catch..final,也可以选择Akka,并发处理和异常处理自成体系,Akka的文档写的不错,从why到how都讲了。不过我觉得还是把协程搞搞好,然后开发连Actor也不用看了,无限执行体,顺序写代码还是很美好的。

    Scala语法差不多也就这样了,整体看,似乎想将代码片段变得更短,从而看起来简洁,也更加容易复用,很爱使用各种符号,看的我有点眼花。


                                                                      图1. 类型体系


[1]. http://docs.scala-lang.org/tutorials/tour/tour-of-scala.html

[2]. https://www.tutorialspoint.com/scala/index.htm

[3]. http://www.familylifemag.com/question/427847/is-it-possible-to-specify-an-anonymous-functions-return-type-in-scala

[4]. https://stackoverflow.com/questions/2005681/difference-between-abstract-class-and-trait

以上是关于Scala简明语法的主要内容,如果未能解决你的问题,请参考以下文章

Cmd Markdown 简明语法手册

Cmd Markdown 简明语法手册

Markdown 简明语法

转 - markdown简明语法

如何从grako / TatSu获取简明的语法错误消息

Cmd Markdown 简明语法手册