基于IDEA安装运行Scala
因为scala是基于jvm的类python语言。。
使用maven添加scala-library的依赖,即可和java无缝使用。
推荐,以后都使用scala来编写java代码。
Bite-sized introductions to core language features. (核心功能概览)
Scala Style Guide(编程风格)
Scala Language Specification (语言手册)
===============================================================
- Classes in Scala are blueprints for creating objects
-
Constructors parameters 也是class的members
- Primary constructor parameters with val and var are public
-
Constructors parameters without val or var are private values, visible only within the class.
- 并且默认是val的,不可reassign
-
Members are public by default.
- Use the private access modifier to hide them from outside of the class.
- Notice the special syntax for the setters: the method has _= appended to the identifier of the getter and the parameters come after.
注意,private members,对应的getter and setter的写法
private
var
_x
=
0 //private members 命名时下划线开头
def
x
=
_x //getter
def
x_=
(
newValue
:
Int
)
:
Unit
=
{ //setter 注意写法
.......
}
Traits are used to share interfaces and fields between classes.
They are similar to Java 8’s interfaces.
- trait可以有abstract field
Classes and objects can extend traits
but traits cannot be instantiated and therefore have no parameters.
but many mixins (using the keywords
extends
and
with
respectively)
The mixins and the superclass must have the same supertype
object
XX e
xtends
App {...}
- 相当于整个object body,都在main Method body之中。可以直接执行
- functions are first-class values in Scala
- salaries.map(x => x * 2) 可以简写为 salaries.map(_ * 2)
函数式编程重要概念:
- 纯函数~没有副作用
- 引用透明~相同的输入,总是得到相同的输出
-
不变性(Immutability)
- 任何值都是不变的,才能获得引用透明
-
函数是一等公民(first class)
- 函数是一种类型。。可以赋给变量
- 高阶函数(high order):函数作为参数或返回值
- 闭包:函数引用外部变量。
- 一切都是表达式,都能计算得值
- 表达式求值策略:严格求值、非严格求值、惰性求值
-
递归函数
- 没有循环。所有循环使用递归实现
- 递归调优:尾递归
- currying柯里化
函数式编程优点
- 简洁(生产效率高)
- 易于推理(确定输入,有确定输出)
- 适用于并行编程(多核计算【计算机多个核心】、云计算【即分布式计算】)
-
作用域保护
- private[x]、protected[x]
- 这里的x指代某个所属的包、类或单例对象
-
字面量(literal)
- 不变量、常量(val)
- 变量(var)
-
for 循环 多层循环
- 使用分号 (;) 构成多层循环
-
for 循环过滤
- Scala 可以使用一个或多个 if 语句来过滤一些元素。
-
for 使用 yield
- 构成generator??
-
Scala 标识符
- 普通标识符,与java标识符规则相同
-
可以使用特殊字符:+, ++, ~, &,-, -- , \, /, : 等
- 一般要么只使用普通标识符、要么只使用特殊符号
- 除private变量的setter等特殊情况外
- 特殊符号 内部实现时会使用转义的标志符,比如:-> 使用 $colon$minus$greater 来表示这个符号
-
java方法名跟scala关键字冲突
- 例如 Thread.`yield`()
如果你不写等于号和方法主体,
那么方法会被隐式声明为"抽象(abstract)",包含它的类型于是也是一个抽象类型。
函数参数(function arguments)解析时有两种方式
-
传名调用(call-by-name)
- 格式是 varName: (argType...) => returnType
-
传值调用(call-by-value)
- 格式是varName : => returnType
-
区别是:
- 传名调用,需要声明参数列表
- 传名调用 传入的是funcName,只有调用【funcName(xxx) 】时,才执行
- 传值调用,传入的是funcName(xxx)的返回值。
可变参数
Scala 允许你指明函数的最后一个参数是可变参数,
在参数的类型之后放一个星号来设置可变参数
偏函数
使用偏函数优化
存在不变参数的函数,
将不变的参数绑定,使用下划线(_)替换缺失的参数列表,并把这个新的函数的引用的赋给变量(即偏函数)。
function的表示方式:
- (varName: varType...) => {expressions}
- 函数返回值是由多个expressions构成的block的值,即最后一个expression的值
- function是object,所以可以赋值给变量
- function调用:加括号,传入参数即可调用
函数柯里化(Currying):举例
-
将函数 【 def add(x:Int,y:Int)=x+y 】柯里化为multiple parameter list的形式
- 【def add(x:Int)(y:Int) = x + y】或【def add(y:Int)(x:Int) = x + y】
- 这样获得的好处是,可以根据参数进行分步调用。。中间每一步返回值都是一个函数。
闭包
- 引用 函数体外面定义的变量(除function args外)的函数,即闭包
-
一般引用的外部变量,不允许改变。比如java中,这样的变量必须以final来声明
- Scala可以使用val来实现类似效果。。但编译器不强制外部变量必须不可变。
在 Scala 中,字符串的类型实际上是 Java String,它本身没有 String 类。
type String = java.lang.String
使用type,来声明type alias
Scala方法调用的简便写法:
- 【 objectName.methodName(args...) 】可以简化为 【 objectName methodName (args...) 】
-
如果args只有一个,可以省略括号
- 注意tuple的概念和python类似
- 如果没有args,括号也可以省略
- 所以AnyVal类型的对象(Int、Double等),都有以+、-、++等运算符号命名的方法。
一个Scala脚本文件与其中的object、class、trait并没有强制的联系
- 一个文件中可以有任意多个object、class、trait
- 在$SCALA_HOME/bin目录中,运行scala,进入REPL模式。可以计算expressions
-
scala脚本文件代码可写的位置:
- 通常在已有package声明的Scala文件中,代码不能写在object、class、trait之外
- 在object、trait之中,不在Method之中的代码,运行在【static initiation(静态初始化)】阶段
- 在class之中,不在Method之中的代码,运行在【instance initiation(实例初始化)】阶段,即new对象时。
数组使用【 arrName(expression)】来索引成员
Tuple可以包含不同类型的元素
生成元组:
- 一般通过圆括号来生成,
- 但内部是通过new内置的TupleXX(...)来生成。
- Scala 支持的元组最大长度为 22。对于更大长度你可以使用集合,或者扩展元组
可以使用 t._1 访问第一个元素, t._2 访问第二个元素
List是不可变的,
tail 返回一个列表,包含除了第一元素之外的其他元素
Set分为可变的和不可变。
默认情况下,Scala 使用的是不可变Set,如果你想使用可变Set,需要引用 scala.collection.mutable.Set 包
不可变集合类,你仍然可以模拟添加,移除或更新操作。
- 但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变。
-
不可变集合,都在 scala.collection.immutable包下
- 可变集合都在scala.collection.mutable包下
-
一般集合,都有成对的可变集合和不可集合存在。比如
- List不可变、ListBuffer可变
- scala.collection.immutable.Set不可变,scala.collection.mutable.Set可变
-
默认推荐使用不可变集合、不可变的变量(val)
- 为什么??
mapVar.get(key)返回一个Option[T]对象
Scala Option(选项)类型用来表示一个值是可选的(有值或无值)
- Option 有两个子类别,一个是 Some,一个是 None,
- 当他回传 Some 的时候,代表这个成功获取值,而你可以透过 get() 拿到那个 值,
- 如果他返回的是 None,则代表没有值返回。
重写一个非抽象方法必须使用override修饰符
- 重写抽象方法时,override关键字可用可不用(推荐加上)
只有一个构造方法
- Scala不存在方法重载,使用函数默认值取代
extends时,需要加上基类的构造方法:
- Location(override val xc: Int, override val yc: Int,val zc :Int) extends Point(xc, yc)
-
伴生对象、伴生类
- 当object与某个class共享同一个名称时,
- object称为伴生对象:companion object。class称为伴生类:companion class。
- 类和它的伴生对象可以互相访问其私有成员
-
私有构造方法:举例
- class Marker private(val color:String)
- 如果定义了apply,就可以使用【ClassName(argVal...)】生成对象
-
如果定义了unapply,
- 可以在模式匹配中使用【ClassName(argVal...) 或者ClassName(argVar...) 】
- 在模式匹配 时,unapply 将自动执行
-
其中unapply,叫做提取器(Extractor)
- 提取器是从传递给它的对象中提取出构造该对象的参数。
-
只有case class和object存在apply、unapply
-
case class的apply、unapply,是自动生成的。
- 自定义的apply、unapply不会覆盖。是普通方法。
- object的apply、unapply必须自定义并实现
-
注意apply~unapply是成对出现的。
- apply的返回值,是unapply的参数。
- unapply的返回值Option[Type...],其中Type...对应apply的参数类型
-
-
模式匹配机制
- match-case方式,类似switch-case
- 可以 类型匹配,用于判断传入的值是否为指定类型
-
样例类(case classes)
- 用于模式匹配。
- 在伴生对象中提供了apply方法,所以可以不使用new关键字就可构建对象
- 提供unapply方法使模式匹配可以工作
- 生成toString、equals、hashCode和copy方法,除非显示给出这些方法的定义
- 类似java bean概念
在Scala里,借用了模式匹配的思想来做异常的匹配,
因此,在catch的代码里,是一系列case字句,
Scala 进行文件写操作,直接用的都是 java中 的 I/O 类 (java.io.File)
使用 Scala 的 Source 类及伴生对象来读取文件:举例
Source.fromFile("test.txt" ).foreach{}
隐式转换
特殊的多变量赋值的写法:
//常见的有Array、Tuple
val
Array(hostname
, port) = Array("localhost", 8080)
// val ar = (2,3)
// val Tuple2(a, b) = ar