JAVA语言脚本化,面向函数,直奔主题。查看帮助:(:help)查看历史:(:history)用var和val定义变量
val:相当于java中的final。
var:其值可变。
if (x>0) 1 =====> if (x>0) 1 else () Unit === Void
【《快学Scala》笔记】
一、基础
1、变量
val 标志符: 声明常量; 如,val answer = 1
var 标志符:声明变量;
鼓励使用val;
注:声明变量时不做初始化会报错。
1 val a:Int = 1 2 val str:String = 2
2、常用类型
Scala支持7种数值类型和1种Boolean类型。
注:所有这些类型都是类,Scala并未区分基本类型与引用类型。如,可以调用1.toString方法。
3、数值类型转换:
Scala中使用方法,而非强制类型转换来做数值类型之间的转换。如,
4、操作符
Scala支持Java中绝大多数操作符,不过所有的操作符都是方法。如:
a+b 是 a.+(b) 的缩写
即:a 方法 b 是 a.方法(b) 的缩写,两种写法可以互换。
【注:Scala不支持 ++ 和 -- 操作符。】
5、函数调用和方法
常用数学函数包括在scala.math包中,可以通过如下语句引入包。
1 import scala.math._ // Scala中,字符 _ 是通配符,类似Java中的*
另外,以scala开头的包,在引入或使用时可以省略scala。
1 import math._ 2 3 math.sqrt(2)
【注:Scala中没有静态方法。】
不带参数的方法在调用时可以省略括号,如:
1 "hello World".toString
6、apply方法
在Scala中通常使用类似函数调用的形式来访问数组、链表等的元素。如:
上述调用中,"hello"(0)是"hello".apply(0)的调用。其中apply方法是StringOps类中的方法。
二、控制结构和函数
1、if语句也有返回值
if语句称为条件表达式,如:
条件表达式的结构为: if( 判断条件 ) 值1 else 值2 ;结构类似于 Java的三目运算符,但是Scala不支持三目运算符。
该条件表达式可以用来初始化val常量。
注:Scala中每个表达式都会返回值,如
条件表达式返回了 () ,其中 () 表示Unit类,表示没有值。可以看作Java中的void类型。
2、Scala不支持switch语句,但是Scala有更强大的模式匹配机制。
3、块表达式
Scala中使用 {} 括起来一系列表达式,其 {} 括起来包括 {} 的部分叫做块表达式,块表达式的值是块中的最后一个表达式的值。如,
可以使用块表达式为变量赋值,如:
变量distance使用块表达式来赋值,其值为块中最后一个表达式的值。
4、Scala中赋值语句的返回值为Unit,也可记作:Scala中赋值语句是没有返回值的。
【注: x = y = 3; 这种赋值形式在Scala中不支持,因为赋值语句在Scala中无返回值。 所以, += 、-= 、 ×= 、/= 等赋值操作符都是无返回值的。】
5、输入、输出
常用的包括readLine从控制台读取一行输入,另外,readLine还可带有提示字符串,如:
readInt、readByte、readDouble、readShort、readLong、readFloat、readBoolean、readChar分别用于读取各自类型的值。
print(内容)、println(内容)、printf; 其中println带换行;另外,printf支持C风格的字符串输出,如:
6、循环操作
Scala支持Java相同的while和do循环:
Scala的for循环结构:( for循环中,变量前面不带var或val标志符)
1 for( 变量 <- 表达式 ){ //让变量遍历表达式的所有值 2 3 //操作 4 5 }
如:
7、for循环的高级用法
1 for( i <- 1 until 3; j <- 1 until 3 ){ 2 println( i*j ) 3 }
for循环的这种结构类似Java中的嵌套循环结构。
另外,可以采用
1 for{ i <- 1 until 3 //使用大括号,使用换行来分隔组 2 j <- 1 until 3 }{ 3 4 println( i*j ) 5 }
if表达式是否添加括号,结果无变化。
until 返回一个不包含上界的区间,如 1 until 3 返回 (1,2);
to方法返回一个包含善洁的区间,如 1 to 3 返回(1,2,3);
如果for循环以yield开始,for循环会构造出一个集合,保存到集合中。
8、Scala并不支持break和continue;
9、函数—Scala支持函数式编程
1 def 函数名(参数1:类型1, 参数2:类型2,... ):返回值类型 = { 2 3 //函数体 4 5 }
例如:
【注:对于有返回值的函数,不能省略 等号 ; 对于递归函数,不能省略函数返回值类型。】
【注:无返回值的函数定义时可以省略 等号 ;无返回值的函数返回类型是 Unit;】
10、带默认值的函数
带默认值函数的声明,与Java中的带默认值的方法很类似。
11、带名参数——在函数调用时通过明确指明参数与其对应值
第一个函数调用为普通调用,第二个函数调用为带名参数调用。
12、长度可变的参数列表
通过在函数的形参列表最后一个参数的类型后,添加*,来定义一个接受任意多个参数的函数。
13、过程,Scala中将没有返回值的函数叫做过程,如上图所示的函数。
过程在定义的时候,参数列表之后无等号。
14、懒值
但val被声明为lazy时,变量的初始化将被延迟,直到我们首次对变量取值。例如:
1 lazy val fileContent = scala.io.Source.fromFile("filename").mkString
只有当我们读取fileContent值时,fileContent才会通过读取文件来进行初始化。若我们一直未读取fileContent值,这文件不会被读取。
15、Scala没有“受检”异常——无需声明函数或方法可能会抛出某种异常。
过程:没有返回值的函数,不使用等号赋值;
赋值类型是Unit(),throw表达式类型是Nothing if/else 类型取决于非抛异常的语句
默认是公有的,scala没有public关键字。私有字段,age和age_=也是私有的。
Dog.scala:class Dog{
var age=0
}
抽象方法:
非抽象方法:
覆盖字段:
子类重写父类抽象字段也不需要加override。
Java中的正则匹配:
apply方法接收构造参数,然后生成对象,unapply接收对象,从中提取值。(unapplyseq)
函数中的参数是函数:
如果参数只在=>右侧出现一次,可以用_代替。(=>这个不用写)
Scala 函数
柯里化(Currying)指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数为参数的函数。
首先我们定义一个函数:
def add(x:Int,y:Int)=x+y
那么我们应用的时候,应该是这样用:add(1,2)
现在我们把这个函数变一下形:
def add(x:Int)(y:Int) = x + y
那么我们应用的时候,应该是这样用:add(1)(2),最后结果都一样是3,这种方式(过程)就叫柯里化。
add(1)(2) 实际上是依次调用两个普通函数(非柯里化函数),第一次调用使用一个参数 x,返回一个函数类型的值,第二次使用参数y调用这个函数类型的值。
实质上最先演变成这样一个方法:
def add(x:Int)=(y:Int)=>x+y
那么这个函数是什么意思呢? 接收一个x为参数,返回一个匿名函数,该匿名函数的定义是:接收一个Int型参数y,函数体为x+y。现在我们来对这个方法进行调用。
val result = add(1)
返回一个result,那result的值应该是一个匿名函数:(y:Int)=>1+y
所以为了得到结果,我们继续调用result。
val sum = result(2)
最后打印出来的结果就是3。
下面是一个完整实例:
object Test { def main(args: Array[String]) { val str1:String = "Hello, " val str2:String = "Scala!" println( "str1 + str2 = " + strcat(str1)(str2) ) } def strcat(s1: String)(s2: String) = { s1 + s2 } }
执行以上代码,输出结果为:
$ scalac Test.scala $ scala Test str1 + str2 = Hello, Scala!
对象不能带泛型。
发消息:act3 !"你的消息"
Message应该定义为样例类:
abstract class AbstractMessage{}
case class Message(a:Int,b:Int,c:Actor) extends AbstractMessage{}
别忘了导包import scala.actors.Actor._
"=>"的用法:
1. 表示函数的类型(Function Type)
例如:
1
|
def
double(x
:
Int)
:
Int
=
x*
2
|
函数double的类型就是 (x: Int) => Int 或者 Int => Int
备注: 当函数只有一个参数的时候,函数类型里面括起来函数参数的括号是可以省略的。
使用函数的类型,就可以定义函数变量(Function Value/Function Variable)
那么现在定义一个函数变量:
var x : (Int) => Int = double
2. 匿名函数(Anonymous functions/Function Literals/Lambda)
例如:通过匿名函数定义一个函数变量xx
var xx = (x: Int) => x + 1
或者,给一个高阶函数,传递一个函数:
val newList = List(1,2,3).map { (x: Int) => x * 2 }
3. By-Name Parameters
假设有如下两个函数:
1
2
3
4
5
6
7
8
9
10
|
def
doubles(x
:
=
> Int)
=
{
println(
"Now doubling "
+ x)
x*
2
}
def
f(x
:
Int)
:
Int {
println(s
"Calling f($i)"
)
i
}
|
那么对于函数doubles而言,它的参数x就是by-name的。如果调用doubles的时候,直接给个普通的值或者非函数变量。那么doubles的执行结果就跟普通的函数没有区别。但是当把一个返回值为Int类型的函数,例如f(2),传递给doubles的时候。那么f(2)会被先计算出返回值2,返回值2传入doubles参与运算。运算完成以后,f(2)会被doubles在执行以后,再调用一遍。
4. case语句
1
2
3
4
5
6
7
8
|
val
x
=
10
;
val
y
=
20
x
:
Int
=
10
y
:
Int
=
20
val
max
=
x > y
match
{
case
true
=
> x
case
false
=
> y
}
max
:
Int
=
20
|