Scala 变量
变量vs常量
在 Scala 中,使用关键词 “var” 声明变量(可以修改),使用关键词 “val” 声明常量(不能修改)。
1 | # 变量(可以修改) |
变量类型声明
var VariableName : DataType [= Initial Value]
变量类型引用
Scala 中声明变量和常量不一定要指明数据类型,在没有指明数据类型
的情况下,其数据类型是通过变量或常量的初始值
推断出来的
1 | var myVar = 10; |
多个变量声明
1 | val xmax, ymax = 100 // xmax, ymax都声明为100 |
Scala 访问修饰符
分别有:private,protected,public,没有指定默认
是public,
私有(Private)成员
Scala 中的 private 限定符,比 Java 更严格,在嵌套类情况下,外层类甚至不能访问被嵌套类的私有成员
1 | class Outer{ |
(new Inner).f( ) 访问不合法
是因为 f 在 Inner 中被声明为 private,而访问不在
类 Inner 之内。但在 InnerMost 里访问 f 就没有问题的,因为这个访问包含在 Inner 类之内
保护(Protected)成员
在 scala 中,对保护(Protected)成员的访问比 java 更严格一些。因为它只允许
保护成员在定义了该成员的的类的子类
中被访问。而在java中,用protected关键字修饰的成员,除了定义了该成员的类的子类
可以访问,同一个包里的其他类
也可以进行访问。
1 | package p { |
Other 对 f 的访问不被允许,因为 other 没有继承自 Super
公共(Public)成员
Scala中,如果没有指定任何的修饰符,则默认
为 public。这样的成员在任何地方都可以被访问。
作用域保护
1 | private[x] 或 protected[x] |
这里的x指代某个所属的包、类或单例对象
。如果写成private[x],读作”这个成员除了对[…]中的类或[…]中的包中的类及它们的伴生对像可见
外,对其它所有类都是private。这种技巧在横跨了若干包的大型项目中非常有用,它允许你定义一些在你项目的若干子包中可见
但对于项目外部的客户
却始终不可见的东西。
1 | class Hello { |
由于私有变量不能被继承,执行会报错
1 | class Hello { |
重新定义了world的作用域,就可以访问了
1 | package scopeA { |
Scala 为用户提供了一些额外方法,以
帮助用户以更小的粒度对可见性
的作用域进行调整。从这一点看,Scala 超过了大多数的语言。Scala 提供了作用域内私有(scoped private)可见性声明和作用域内受保护(scoped protected)可见性声明。请注意,在具有继承关系
的情况下,`对类成应用这两类可见性后表现不同。但除此之外,这两类可见性的表现完全一致,因此在同一个作用域内,私有可见性可以和受保护可见性交换使用。
Scala 运算符
符号 | 描述 |
---|---|
/ | 除号 |
% | 取余 |
&& | 逻辑与 |
` | |
! |
逻辑非 |
>>> |
无符号右移 |
>> |
右移 |
右移与无符号右移区别:
- 右移>> :该数对应的二进制码整体右移,左边的用原有标志位补充,右边超出的部分舍弃。
- 无符号右移>>> :不管正负标志位为0还是1,将该数的二进制码整体右移,左边部分总是以0填充,右边部分舍弃
运算符优先级
Scala 运算符
操作符
1 | scala> "A"::"B"::Nil |
scala中:: , +:, :+, :::, +++的区别
Scala 方法与函数
Scala 中的函数则是一个完整的对象,Scala 中的函数其实就是继承了 Trait 的类的对象。
Scala 中使用 val 语句可以定义函数,def 语句定义方法。
1 | class Test{ |
如果方法没有返回值,可以返回为 Unit
,这个类似于 Java 的 void
, 实例如下:
1 | object Hello{ |
函数
Scala 函数传名调用(call-by-name)
Scala的解释器在解析函数参数(function arguments)时有两种方式:
- 传值调用(call-by-value):先计算参数表达式的值,再应用到函数内部;
- 传名调用(call-by-name):将未计算的参数表达式直接应用到函数内部
在进入函数内部前
,传值调用方式就已经将参数表达式的值计算完毕
,而传名调用是在函数内部进行参数表达式的值计算的。这就造成了一种现象,每次使用传名调用时,解释器都会计算一次表达式的值
1 | object Test { |
Scala 指定函数参数名
我们也可以通过指定函数参数名,并且不需要按照顺序
向函数传递参
1 | object Test { |
Scala 函数 - 可变参数
Scala 通过在参数的类型之后放一个星号来设置可变参数(可重复的参数)
1 | object Test { |
Scala 递归函数
Scala 函数 - 默认参数值
Scala 可以为函数参数指定默认参数值,使用了默认参数
,你在调用函数的过程中可以不需要传递参数
,这时函数就会调用它的默认参数值,如果传递了参数
,则传递值会取代
默认值
1 | object Test { |
Scala 高阶函数
Scala 中允许使用高阶函数, 高阶函数可以使用其他函数作为参数
1 | object Test { |
Scala 函数嵌套
我们可以在 Scala 函数内定义函数,定义在函数内的函数称之为局部函数。
1 | object Test { |
Scala 匿名函数
1 | var inc = (x:Int) => x+1 |
Scala 偏应用函数
Scala 偏应用函数是一种表达式,你不需要提供函数需要的所有参数,只需要提供部分,或不提供所需参数。
1 | import java.util.Date |
Scala 函数柯里化(Currying)
闭包
闭包出现是因为lexical scope,闭包是由函数和环境组成,Scala应该支持函数作为参数或返回值,这时如果没有闭包,那么函数的free 变量就会出错
闭包源于λ表达式,它的概念核心分为两块,1.上下文环境 2.控制流程。进一步地说,闭包是绑定了自由变量的函数实例。通常来讲,闭包地实现机制是定义一个特殊的数据结构,保存了函数地址指针与闭包创建时的函数的词法环境以及绑定自由变量。对于闭包最好的解释,莫过于《流程的Python》里给出的“它是延伸了作用域的函数,其中包括函数定义体引用,但是不在定义体定义的非全局变量。核心在于闭包能够访问定义体之外定义的非全局变量。
闭包 = 代码 + 用到的非局部变量
1 | scala> var more =1 |
它“捕获”自身的自由变量(more)从而“闭合”该匿名函数
在Scala里“捕获”的是变量本身,而不是变量本身引用的值。
1 | scala> more = 100 |
当然,反过来也是成立的,闭包也可以修改其自由变量
1 | scala> val minusOne = (x:Int) => {more = more - x} |
那么问题来了,如果more这个变量随着程序的运行被修改了很多次,那么闭包会选择哪一个呢?Scala的答案是,闭包被创建时这个变量最新的那个。(根据定义函数的词法作用域计算自由变量)
1 | scala> def Increase(more:Int) = (x:Int) => x + more |
Scala 字符串
- 在 Scala 中,字符串的类型实际上是 Java String,它本身没有 String 类
- String 对象是不可变的,如果你需要创建一个可以修改的字符串,可以使用 String Builder 类
1
2
3
4
5
6
7
8object Test {
def main(args: Array[String]) {
val buf = new StringBuilder;
buf += 'a'
buf ++= "bcdef"
println( "buf is : " + buf.toString );
}
}
Scala 数组
声明数组
1 | var z:Array[String] = new Array[String](3) |
赋值
1 | z(0) = "Runoob"; z(1) = "Baidu"; z(2) = "Google" |
数组遍历
1 | object Closures { |
多维数组
1 | import scala.Array._ |
Scala Collection
Scala 集合分为可变
的和不可变
的集合
- 可变集合可以在适当的地方被更新或扩展。这意味着你可以修改,添加,移除一个集合的元素。
- 不可变集合类,相比之下,永远不会改变。不过,你仍然可以模拟添加,移除或更新操作。但是这些操作将在每一种情况下都返回一个新的集合,同时使原来的集合不发生改变
1 | val x = List(1, 3, 4, 5) |
Scala Iterator(迭代器)
Scala Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法。迭代器 it 的两个基本操作是 next 和 hasNext。
模式匹配
语法:
1 | import scala.util.Random |