Scala安装及入门基础语法集合
安装
首先安装jdk及配置环境变量,这里就不做介绍了,直接介绍安装scala工具,我使用mac,所以使用brew安装
brew install scala
brew install sbt
安装完毕之后,在终端输入scala查看Scala及jdk的版本,并且进入Scala的解释器
Last login: Fri Jun 12 09:39:20 on ttys000
➜ ~ scala
Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_65).
Type in expressions to have them evaluated.
Type :help for more information.
scala>
变量
Scala的变量分为两种:var和val,var是可变的,可以在它的生命周期中被多次赋值,而val类似于Java里的final变量,一旦初始化后就不能再赋值。
scala> val str="Hello,World!"
str: String = Hello,World!
//如果是尝试给它重新赋值就会出现下面的错误
scala> str="Hi"
<console>:8: error: reassignment to val
str="Hi"
^
scala>
scala> println(str)
Hello,World!
scala>
这个语句引入了str当作字符串的变量名称,类型是java.lang.String,因为Scala的字符串是由Java的String类实现的
上面定义的str变量没有指定变量类型,Scala解释器会自动推断出其类型,当然你也可以显示标准变量类型,如下:
scala> var str: String="How are you"
str: String = How are you
scala>
如果你定义一个变量并且想随时修改它的值,你可以选择使用var修饰符
scala> var color="red"
color: String = red
scala> color="white"
color: String = white
scala> println(color)
white
scala>
如果var变量的赋值为_,则表示使用缺省值(0,false,null),例如:
scala> var d: Double=_
d: Double = 0.0
scala> var i: Int=_
i: Int = 0
scala> var s: String=_
s: String = null
var t: T=_ //泛型T对应的默认值
Scala也可以像使用Python一样方便的赋值
//给多个变量赋同一个值
scala> val x,y=6
x: Int = 6
y: Int = 6
//同时定义多个变量,注意:val x,y=10,"hello"是错误的
scala> val (x,y)=(6,"how are you")
x: Int = 6
y: String = how are you
//::方法聚合,是从左向右开始
scala> val x::y=List(1,2,3,4)
x: Int = 1
y: List[Int] = List(2, 3, 4)
//a=1,b=2,c=3
scala> var List(a,b,c)=List(1,2,3)
a: Int = 1
b: Int = 2
c: Int = 3
//用List,Seq
scala> val Array(a,b,_,_,c@_*)=Array(1,2,3,4,5,6,7)
a: Int = 1
b: Int = 2
c: Seq[Int] = Vector(5, 6, 7) //_*匹配0个到多个
使用正则表达式赋值
scala> val regex="(\\d+)/(\\d+)/(\\d+)".r
regex: scala.util.matching.Regex = (\d+)/(\d+)/(\d+)
scala> val regex(year,month,day)="2015/06/12"
year: String = 2015
month: String = 06
day: String = 12
除了使用val,你还可以使用lazy
- val:定义时就一次求值完成,保持不变
- lazy:定义时不求值,第一次使用时完成求值,保持不变
表达式
scala> 1 + 1
res0: Int = 2
res0是解释器自动创建的变量名称,用来指代表达式的计算结果。它是Int类型,值为2。 打印”Hello,World!”
scala> pringln("Hello,World!")
Hello,World!
基本类型
Scala中的一些基本类型包括:Byte、Short、Int、Long、Char、String、Float、Double、Boolean等,除了String归于java.lang包之外,其余所有的基本类型都是包scala的成员。如Int的全名是scala.Int。然而,由于包scala和java.lang的所有成员都被每个Scala源文件自动引用,你可以在任何地方只用简化名。
Scala的基本类型与Java的对应类型范围完全一样,这让Scala编译器能直接把Scala的值类型在它产生的字节码里转译成Java原始类型
Scala用Any统一了原生类型和引用类型
Any
AnyRef
java String
其他Java类型
ScalaObject
AnyVal
scala Double
scala Float
scala Long
scala Int
scala Short
scala Unit
scala Boolean
scala Char
scala Byte
对于基本类型,可以用asInstanseOf[T]方法来强制转换类型:
scala> val i=10.asInstanceOf[Double]
i: Double = 10.0
scala> List('A','B','C').map(c => (c+32).asInstanceOf[Char])
res2: List[Char] = List(a, b, c)
用isInstanceOf[T]方法来判断类型,但是在match…case中可以直接判断:
scala> val a=1.isInstanceOf[Int]
a: Boolean = true
scala> val b=1.isInstanceOf[Double]
b: Boolean = false
操作符和方法
Scala为它的基本类型提供了丰富的操作符,例如,1 + 2与(1).+(2)其实是一回事。换句话说,就是 Int 类包含了叫做+的方法,它带一个 Int 参数并返回一个 Int 结果。这个+方法在两 个 Int 相加时被调用:
scala> val sum = 1 + 2 // Scala调用了(1).+(2)
sum: Int = 3
//也可以显示的写成方法调用
scala> val sumMore = (1).+(2)
sumMore: Int = 3
而真正的事实是,Int包含了许多带不同的参数类型的重载的+方法。
符号+是操作符——更明确地说,是中缀操作符。操作符标注不仅限于像+这种其他语言里 看上去像操作符一样的东西。你可以把任何方法都当作操作符来标注。例如,类 String 有一个方法 indexOf 带一个 Char 参数。indexOf 方法搜索 String 里第一次出现的指定字符,并返回它的索引或 -1 如果没有找到。你可以把 indexOf 当作中缀操作符使用,就像这样
scala> val str="are you ready"
str: String = are you ready
scala> str indexOf 'o' //scala调用了str.indexOf('o')
res3: Int = 5
scala>
String 提供一个重载的 indexOf 方法,带两个参数,分别是要搜索的字符和从哪个索引开始搜索。尽管 这个 indexOf 方法带两个参数,你仍然可以用操作符标注的方式使用它
scala> str indexOf ('e',4)
res4: Int = 9
scala>
在Scala中任何方法都可以是操作符
Scala 还有另外两种操作符标注:前缀和后缀。前缀标注中,方法名被放在调用的对象之前,如,-7 里的-。后缀标注在方法放在对象之后,如7 toLong里的toLong。
与中缀操作符——-操作符带后两个操作数,一个在左一个在右,相反,前缀和后缀操作符都是一元 unary 的:它们仅带一个操作数。前缀方式中,操作数在操作符的右边。前缀操作符的例子有 -2.0、!found和~0xFF。与中缀操作符一致,这些前缀操作符是在值类型对象上调用方法的简写方式。然而这种情况下,方法名在操作符字符上前缀了unary_。 例如,Scala 会把表达式 -2.0 转换成方法调用(2.0).unary_-。你可以输入通过操作符和显式方法名两种方式对方法的调用来演示这一点
scala> -2.0 // Scala调用了(2.0).unary_- res2: Double = -2.0
scala> (2.0).unary_-
res32: Double = -2.0
可以当作前缀操作符用的标识符只有+,-,!和~
- 后缀操作符是不用点或括号调用的不带任何参数的方法
scala> val str="Are You OK"
str: String = Are You OK
scala> str.toLowerCase
res10: String = are you ok
scala> str toLowerCase
res11: String = are you ok
### 数学运算操作符 Int无++、–操作,但是可以有+=、-=,如下:
scala> var i=1
i: Int = 1
scala> i+=2
scala> println(i)
3
scala> i-=2
scala> println(i)
1
对象相等性
比较两个对象是否相等,可以使用==,或它的反义!=
//比较基本类型
scala> 1 == 2
res36: Boolean = false
scala> 1 != 2
res37: Boolean = true
scala> 2 == 2
res38: Boolean = true
//比较对象
scala> List(1, 2, 3) == List(1, 2, 3)
res39: Boolean = true
scala> List(1, 2, 3) == List(4, 5, 6)
res40: Boolean = false
//比较不同类型
scala> 1 == 1.0
res41: Boolean = true
scala> List(1, 2, 3) == "hello"
res42: Boolean = false
//和null进行比较,不会有任何异常抛出
scala> List(1, 2, 3) == null
res43: Boolean = false
scala> null == List(1, 2, 3)
res44: Boolean = false
scala> null == List(1, 2, 3)
res45: Boolean = false
Scala的 == 很智能,他知道对于数值类型要调用Java中的 == ,引用类型要调用Java的equals():
scala> var str="Hi"
str: String = Hi
scala> str=="Hi"
res19: Boolean = true
//注意它和java一样是区分大小写的
scala> str=="hi"
res20: Boolean = false
Scala的==总是内容对比,eq是引用对比
scala> val s1,s2="logic"
s1: String = logic
s2: String = logic
scala> val s3=new String("logic")
s3: String = logic
scala> s1==s1
res21: Boolean = true
scala> s1 eq s2
res22: Boolean = true
scala> s1==s3
res23: Boolean = true
scala> s1 eq s3
res24: Boolean = false
富包装器
Scala的每个基本类型都有一个富包装类,例如:Int: scala.runtime.RichInt
scala> 0 max 5
res25: Int = 5
scala> -2.7 abs
warning: there was one feature warning; re-run with -feature for details
res26: Double = 2.7
scala> -2.7 round
warning: there was one feature warning; re-run with -feature for details
res27: Long = -3
scala> 4 to 6
res28: scala.collection.immutable.Range.Inclusive = Range(4, 5, 6)
scala> "bob" capitalize
warning: there was one feature warning; re-run with -feature for details
res29: String = Bob
scala> "robert" drop 2
res30: String = bert
函数
函数的地位和一般的变量是同等的,可以作为函数的参数,可以作为返回值。传入函数的任何输入是只读的,比如一个字符串,不会被改变,只会返回一个新的字符串。
Java里面的一个问题就是很多只用到一次的private方法,没有和使用它的方法紧密结合;Scala可以在函数里面定义函数,很好地解决了这个问题。
函数定义
函数和方法一般用def定义
def max(x: Int,y: Int): Int={
if(x>y) x else y
}
有时候Scala编译器会需要你定义函数的结果类型。比方说,如果函数是递归的,你就必须显式地定义函数结果类型。然而在max的例子里,你可以不用写结果类型,编译器也能够推断它。同样,如果函数仅由一个句子组成,你可以可选地不写大括号。这样,你就可以把max函数写成这样
scala> def max(x: Int, y: Int) = if (x > y) x else y
scala> max(2,6)
res0: Int=6
函数不带参数,调用时可以省略括号
scala> def noParam()=3+8
noParam: ()Int
scala> noParam()
res31: Int = 11
scala> noParam
res32: Int = 11
既不带参数也不会有返回值的函数定义
scala> def noReturn() =println("console")
noReturn: ()Unit
当你定义了greet()函数,解释器会回应一个greet: ()Unit。空白的括号说明函数不带参数。Unit 是 greet 的结果类型,Unit 的结果类型指的是函数没有返回有用的值。Scala 的 Unit 类型比较接近 Java 的 void 类型,而且实际上 Java 里 每一个返回 void 的方法都被映射为 Scala 里返回 Unit 的方法。
总结:
- 函数体没有像Java那样放在{}里,Scala 中的一条语句其实是一个表达式
- 如果函数体只包含一条表达式,则可以省略{}
- 函数体没有显示的return语句,最后一条表达式的值会自动返回给函数的调用者
- 没有参数的函数调用时,括号可以省略
映射试定义
一种特殊的定义:映射式定义(直接相当于数学中的映射关系);其实也可以看成是没有参数的函数,返回一个匿名函数;调用的时候是调用这个返回的匿名函数
def f:Int=>Double = {
case 1 => 0.1
case 2 => 0.2
case _ => 0.0
}
f(1) // 0.1
f(3) // 0.0
def m:Option[User]=>User = {
case Some(x) => x
case None => null
}
m(o).getOrElse("none...")
def m:(Int,Int)=>Int = _+_
m(2,3) // 5
def m:Int=>Int = 30+ // 相当于30+_,如果唯一的"_"在最后,可以省略
m(5) // 35
def fibonacci(in: Any): Int=in match {
case 0 =>0
case 1 =>1
case n: Int if(n>1) => fibonacci(n-1)+fibonacci(n-2)
case n: String => fibonacci(n.toInt)
case _ => 0
}
特殊函数 + - * /
在Scala中方法名可以是+
、-
、*
、/
def +(x:Int,y:Int)={x+y}
+(1,2) //200
1+2相当于1.+(2)
函数调用
- 不在class或者Object中得函数不能如此调用
def m(i:Int) = i*i
m 10 // 错误
- 但在calss或者object中可以使用this调用
object method {
def m(i:Int) = i*i
def main(args: Array[String]) = {
val ii = this m 15 // 等同于 m(15), this 不能省略
println(ii)
}
}
匿名函数
形式:((命名参数列表)=>函数实现)(参数列表)
特殊情况:
- 无参数:
(()=>函数实现)()
- 有一个参数且在最后:
(函数实现)(参数)
- 无返回值:
无返回值: ((命名参数列表)=>Unit)(参数列表)
1、使用=>
创建匿名函数
scala> (x: Int) => x+1
res35: Int => Int = <function1>
scala> x:Int => x+1
<console>:1: error: ';' expected but '=>' found.
x:Int => x+1
^
scala> {(x: Int) => x+1}
res36: Int => Int = <function1>
scala> {x: Int => x+1}
res37: Int => Int = <function1>
2、函数值是对象,所以如果你愿意可以把它们存入变量。它们也是函数,所以你可以使用通常的括 号函数调用写法调用它们
scala> val param1=(x: Int) => x+1
param1: Int => Int = <function1>
//不用(),而用{}
scala> val param2={x: Int => x+1}
param2: Int => Int = <function1>
scala> param1(20)
res38: Int = 21
scala> param2(60)
res39: Int = 61
3、有参数的匿名函数的调用
scala> ((i: Int) => i * i)(2)
res40: Int = 4
scala> ((i: Int,j: Int) => i+j)(5,6)
res41: Int = 11
4、有一个参数且在最后的匿名函数的调用
//相当于((x:Int)=>1*x)(3)
scala> (1*)(3)
res42: Int = 3
//相当于((x:Int) => 1+x)(2)
scala> (1+)(2)
res43: Int = 3
scala> (List("a","b","c") mkString)("=")
res44: String = a=b=c
5、无参数的匿名函数调用
scala> (() => 1)()
res45: Int = 1
6、无参数返回值
scala> (() => Unit)
res46: () => Unit.type = <function0>
//相当于调用一段方法
scala> (() => {println("hi"); 2+1})()
hi
res49: Int = 3
匿名函数的例子
//例子1:直接使用匿名函数
//这里对变量i使用了类型推断
scala> List(1,2,3).map((i:Int) => i*i)
res50: List[Int] = List(1, 4, 9)
//例子2:无参数的匿名函数
scala> def loop(m:() => Unit) ={ m();m();m();}
loop: (m: () => Unit)Unit
scala> loop(() => println("print"))
print
print
print
//上面例子2由于是无参数的匿名函数,可进一步简化
scala> def loop(m: => Unit) ={ m;m;m;}
loop: (m: => Unit)Unit
scala> loop(println("print"))
print
print
print
偏应用函数(Partail application)
用下划线代替一个或多个参数的函数叫偏应用函数,例如:
//定义函数
scala> def sum(a: Int, b: Int, c: Int) = a + b + c
sum: (Int,Int,Int)Int
//把函数sum应用到参数1、2、3上
scala> sum(1,2,3)
res51: Int = 6
偏应用函数是一种表达式,你不需要提供函数需要的所有参数。代之以仅提供部分,或不提供所需参数。比如,要创建不提供任何三个所需参数的调用sum的偏应用表达式,只要在“sum”之后放一个下划线即可,然后可以把得到的函数存入变量。举例如下:
scala> val a = sum _
a: (Int, Int, Int) => Int = <function>
有了这个代码,Scala 编译器以偏应用函数表达式sum _
,实例化一个带三个缺失整数参数的函数值,并把这个新的函数值的索引赋给变量 a。当你把这个新函数值应用于三个参数之上时,它就转回头调用 sum,并传入这三个参数:
scala> a(1, 2, 3)
res2: Int = 6
实际发生的事情是这样的:名为a的变量指向一个函数值对象。这个函数值是由Scala编译器依照偏应用函数表达式sum _
,自动产生的类的一个实例。编译器产生的类有一个apply
方法带三个参数。之所以带三个参数是因为sum _
表达式缺少的参数数量为三。Scala编译器把表达式a(1,2,3)翻译成对函数值的apply
方法的调用,传入三个参数 1、2、3。因此 a(1,2,3)是下列代码的短格式:
scala> a.apply(1, 2, 3)
res3: Int = 6
也可针对部分参数使用:
scala> val b = sum(1, _: Int, 3)
b: (Int) => Int = <function>
scala> b(2)
res4: Int = 6
如果_
在最后,则可以省略
1 to 5 foreach println
1 to 5 map (10*)
柯里化函数
有时会有这样的需求:允许别人在你的函数上应用一些参数,然后又应用另外的一些参数 例如一个乘法函数,在一个场景需要选择乘数,而另一个场景需要选择被乘数
scala> def multiply(m: Int)(n: Int): Int = m * n
multiply: (m: Int)(n: Int)Int
你可以直接传入两个参数
scala> multiply(3)(4)
res6: Int = 12
你可以填上第一个参数并且部分应用第二个参数
val ts=multiply(2) _
ts: (Int) => Int = <function1>
scala> ts(3)
res7: Int =6
你可以对任何多参数函数执行柯里化
scala> (multiply _).curried
res1: (Int) => (Int) => Int = <function1>
可变长度参数
这是一个特殊的语法,可以向方法传入任意多个同类型的参数,例如:
def test(args: String*)={
args.map{arg => arg.capitalize}
}
scala> test("jack","like")
res0: Seq[String]=ArrayBuffer(Jack,Like)
函数内部,重复参数的类型是声明参数类型的数组。因此,capitalizeAll函数里被声明为类型“String*” 的args的类型实际上是 Array[String]。然而,如果你有一个合适类型的数组,并尝试把它当作重复参数传入,你会得到一个编译器错误:
scala> val arr = Array("Are", "you", "ready?")
scala> test(arr)
<console>:31: error: type mismatch;
found : Array[String]
required: String
test(arr)
^
要实现这个做法,你需要在数组参数后添加一个冒号和一个_*符号(这个标注告诉编译器把arr的每个元素当作参数,而不是当作单一的参数传给test),像这样:
scala> test(arr: _*)
res2: Seq[String] = ArrayBuffer(Are, You, Ready?)
lazy参数
调用时用到函数的该参数,每次都重新计算
lazy参数当做变量或者值的示例
//一般参数
def f1(x: Long) = {
val (a,b) = (x,x)
println("a="+a+",b="+b)
}
f1(System.nanoTime)
//a=1429501936753731000,b=1429501936753731000
//lazy参数
def f2(x: =>Long) = {
val (a,b) = (x,x)
println("a="+a+",b="+b)
}
f2(System.nanoTime)
//a=1429502007512014000,b=1429502007512015000
lazy参数当做函数时的示例
//一般参数,打印一次
scala> def times1(m: Unit) = { m;m;m }
times1: (m: Unit)Unit
scala> times1 ( println("How are you") )
How are you
//lazy参数,打印三次
scala> def times2(m: =>Unit) = { m;m;m }
times2: (m: => Unit)Unit
scala> times2 ( println("How are you") )
How are you
How are you
How are you
流程控制
if..else表达式
if (x>0) 1 else 0
while
//求和
def sum(xs: List[Int]) = {
var total,index=0
while(index < xs.size){
total+=xs(index)
index+=1
}
total
}
//与之对应的do...while循环
var line=""
do{
line=readLine()
pringln("Read:"+line)
} while (line!=null)
循环操作
1、for
//循环中的变量不用定义
scala> for(i<-1 to 5; j=i+i) print(j+" ") //包含上线,例如5
2 4 6 8 10
scala> for(i<-1 until 5; j=i+i) print(j+" ") //不包含上线,例如5
2 4 6 8
//如果for条件是多行,不能用(),而要用{}
for{i<-0 to 3
j<-0 to 2} yield i+j
//带有过滤条件,如果有多个条件,逗号分隔
for(i <- 1 unitl 5 if i%2==1) println(i)
//for中得嵌套循环,包括多个<-
for{ i<-0 to 3; j<-1 until 5} println(i+j)
for yield:把每次循环的结果移近
一个集合(类型和循环内一致)格式:for {子句} yield {循环体}
scala> for(i <- List(1,2,3)) yield (i*i)
res7: List[Int] = List(1, 4, 9)
scala> for(i <- List(1,2,3)) yield {i*i}
res8: List[Int] = List(1, 4, 9)
scala> for(i <- List(1,2,3)) yield i*i
res9: List[Int] = List(1, 4, 9)
2.foreach
scala> List(1,2,3).foreach(println)
1
2
3
scala> (1 to 3).foreach(println)
1
2
3
scala> (1 until 3) foreach(println)
1
2
scala> Range(1,4) foreach println
1
2
3
//可以写步长
scala> 1 to (6,2)
res8: scala.collection.immutable.Range.Inclusive = Range(1, 3, 5)
scala> 1 to 6 by 2
res9: scala.collection.immutable.Range = Range(1, 3, 5)
scala> 1 until (6,2)
res10: scala.collection.immutable.Range = Range(1, 3, 5)
scala> 1 until 6 by 2
res11: scala.collection.immutable.Range = Range(1, 3, 5)
scala> var str=(1 to 6 by 3)
str: scala.collection.immutable.Range = Range(1, 4)
scala> (1:BigInt) to 5
res12: scala.collection.immutable.NumericRange.Inclusive[BigInt] = NumericRange(1, 2, 3, 4, 5)
3.forall:判断是否所有都符合——相当于 A1 && A2 && A3 && … && Ai && … && A
scala> (1 to 3) forall (0<)
res0: Boolean = true
scala> (-1 to 3) forall (0<)
res1: Boolean = false
scala> def isPrime(n:Int) = 2 until n forall (n%_!=0)
isPrime: (n: Int)Boolean
scala> for (i<-1 to 10 if isPrime(i)) print(i+" ")
1 2 3 5 7
scala> (2 to 10) partition (isPrime _)
res14: (scala.collection.immutable.IndexedSeq[Int], scala.collection.immutable.IndexedSeq[Int]) = (Vector(2, 3, 5, 7),Vector(4, 6, 8, 9, 10))
//也可以直接调用BigInt的内部方法
scala> (2 to 10) partition (BigInt(_) isProbablePrime(10))
res15: (scala.collection.immutable.IndexedSeq[Int], scala.collection.immutable.IndexedSeq[Int]) = (Vector(2, 3, 5, 7),Vector(4, 6, 8, 9, 10))
4.reduceLeft方法首先应用于前两个元素,然后再应用于第一次应用的结果和接下去的一个元素,等等,直至整个列表
//计算阶乘
scala> def fac(n: Int) = 1 to n reduceLeft(_*_)
fac: (n: Int)Int
scala> fac(5) // 5*4*3*2 = 120
res6: Int = 120
//求和
scala> List(2,4,6).reduceLeft(_+_)
res7: Int = 12
//取max:
scala> List(1,4,9,6,7).reduceLeft( (x,y)=> if (x>y) x else y )
res8: Int = 9
//或者简化为:
scala> List(1,4,9,6,7).reduceLeft(_ max _)
res9: Int = 9
5.foldLeft 它把状态从一个元素传播到另一个元素。比如说,要算出一个列表里所有元素的和,你需要累加它们,并在切换元素的时候保存中间的计数:
//累加
scala> def sum(L: Seq[Int]) = L.foldLeft(0)((a, b) => a + b)
sum: (L: Seq[Int])Int
scala> def sum(L: Seq[Int]) = L.foldLeft(0)(_ + _)
sum: (L: Seq[Int])Int
scala> def sum(L: List[Int]) = (0/:L){_ + _}
sum: (L: List[Int])Int
scala> sum(List(1,3,5,7))
res10: Int = 16
//乘法:
scala> def multiply(L: Seq[Int]) = L.foldLeft(1)(_ * _)
multiply: (L: Seq[Int])Int
scala> multiply(Seq(1,2,3,4,5))
res11: Int = 120
scala> multiply(1 until 5+1)
res12: Int = 120
6.scanLeft
List(1,2,3,4,5).scanLeft(0)(_+_) // (0,1,3,6,10,15)
//相当于:
(0,(0+1),(0+1+2),(0+1+2+3),(0+1+2+3+4),(0+1+2+3+4+5))
List(1,2,3,4,5).scanLeft(1)(_*_) // (1,2,6,24,120)
//相当于:
(1, 1*1, 1*1*2, 1*1*2*3, 1*1*2*3*4, 1*1*2*3*4*5)
注:
- (z/: List(a,b,c))(op) 相当于 op(op(op(z,a),b),c) 简单来说:加法用0,乘法用1
- (List(a, b, c) :\ z) (op) equals op(a, op(b, op(c, z))
7.take、drop、splitAt
1 to 10 by 2 take 3 // Range(1, 3, 5)
1 to 10 by 2 drop 3 // Range(7, 9)
1 to 10 by 2 splitAt 2 // (Range(1, 3),Range(5, 7, 9))
8.takeWhile、dropWhile、span:
takeWhile (…) | 等价于:while (…) { take } |
dropWhile (…) | 等价于:while (…) { drop } |
span (…) | 等价于:while (…) { take; drop } |
1 to 10 takeWhile (_<5) // (1,2,3,4)
1 to 10 takeWhile (_>5) // ()
10 to (1,-1) takeWhile(_>6) // (10,9,8,7)
1 to 10 takeWhile ( n=> n*n<25) // (1, 2, 3, 4)
1 to 10 dropWhile (_<5) // (5,6,7,8,9,10)
1 to 10 dropWhile (n=>n*n<25) // (5,6,7,8,9,10)
1 to 10 span (_<5) // ((1,2,3,4),(5,6,7,8)
List(1,0,1,0) span (_>0) // ((1), (0,1,0))
//注意,partition是和span完全不同的操作
List(1,0,1,0) partition (_>0) // ((1,1),(0,0))
match表达式
Scala 的匹配表达式允许你在许多可选项中做选择,就好象其它语言中的 switch 语句。通常说来 match 表达式可以让你使用任意的模式
val firstArg = if (args.length > 0) args(0) else ""
firstArg match {
case "scala" | "salts"=> println("scala")
case "java" => println("java")
case "python" => println("python")
case _ => println("other")
}
与 Java 的 switch 语句比,匹配表达式还有一些重要的差别
- case 后面可以是任意类型
- 每个可选项的最后并没有 break,break 是隐含的
- match 表达式也能产生值
val firstArg = if (!args.isEmpty) args(0) else ""
val friend =
firstArg match {
case "scala" | "scala language" => "scala"
case "java" => "java"
case "python" => "python"
case _ => "other"
}
println(friend)
case if 表达式
//写法1:
(1 to 20) foreach {
case x if (x % 15 == 0) => printf("%2d:15n\n",x)
case x if (x % 3 == 0) => printf("%2d:3n\n",x)
case x if (x % 5 == 0) => printf("%2d:5n\n",x)
case x => printf("%2d\n",x)
}
//写法2
(1 to 20) map (x=> (x%3,x%5) match {
case (0,0) => printf("%2d:15n\n",x)
case (0,_) => printf("%2d:3n\n",x)
case (_,0) => printf("%2d:5n\n",x)
case (_,_) => printf("%2d\n",x)
})
break、continue
Scala中没有break和continue语法,需要break得加辅助boolean变量,或者用库(continue没有) 例子1:打印’a’ to ‘z’ 的前5个
var i=0; val rt = for(e<-('a' to 'z') if {i=i+1;i<=5}) printf("%d:%s\n",i,e)
('a' to 'z').slice(0,5).foreach(println)
例子2:1 to 100和小雨1000的数
var (n,sum)=(0,0); for(i<-0 to 100 if (sum+i<1000)) { n=i; sum+=i }
// n = 44, sum = 990
例子3:使用库来实现break
import scala.util.control.Breaks._
for(e<-1 to 10) { val e2 = e*e; if (e2>10) break; println(e) }
try…catch…finally
var f = openFile()
try {
f = new FileReader("input.txt")
} catch {
//捕获异常使用的是模式匹配
case ex: FileNotFoundException => // Handle missing file
case ex: IOException => // Handle other I/O error
} finally {
f.close()
}
其他
Null,None,Nil,Nothing
- Null: Trait,唯一实例为null,是AnyRef的子类,不是AnyVal的子类
- Nothing:Trait,所有类型(包括AnyRef和AnyVal)的子类,没有实例
- None:Option的两个子类之一,另一个是Some,用于安全的函数返回值
- Unit: 无返回值的函数的类型,和java的void对应
- Nil: 长度为0的List
区分<-,=>,->
<-用于for循环
for(i <- 0 to 10)
=>用于匿名函数,也可用在import中定义别名:import javax.swing.{JFrame=>jf}
List(1,2,3).map(x=> x*x)
((i:Int)=>i*i)(5) // 25
->用于Map初始化
Map(1->"a",2->"b") // (1:"a",2:"b")
注意:在scala中任何对象都能调用->方法(隐式转换),返回包含键值对的二元组! ###参考资料
- http://www.scala-lang.org/
- 面向 Java 开发人员的 Scala 指南系列
- Scala语言规范
- Scala编程
- Programming-in-Scala(2nd Edition)
- 快学Scala
- 深入理解Scala