章节
1.基础[ ⬆TOP](#start)
- 在REPL中可以输入:paste来粘贴代码进去,ctrl+d结束。
2.:quit推出REPL,:help显示帮助 - 在Scala中赋值动作是没有值的,或者是Unit类型,所以
x = y = 1 //赋值语句值是Unit类型,所以别把他们串接在一起,y=1值是()
- Scala没有++和–,使用+=和-=代替
java中,a=a+1会被强制转换为更高的数据类型,a+=1不会被转换类型,也就是数据类型不变,两个计算结果一样的。还有+=的执行效率会稍微高一点,结果一样。区别的举例如下:
a+=b –> a=(a.Type)(a+b);//返回的是a类型
a=a+b –> a=a+b;//返回类型是a类型与b类型中的最高类型
2.控制结构和函数[ ⬆TOP](#start)
本章要点:
- if表达式有值
- 块也有值–是它最后一个表达式的值
- Scala的for循环就像增强版的Java for循环
- 分号不是必须的,void类型是Unit,避免在函数定义中使用return
- 注意别再函数式定义中漏掉=。
- 异常工作方式与Java和C++中基本一样,不同的是再catch语句中使用“模式匹配”
- Scala没有受检异常
- Scala中没有switch语句,提供模式匹配机制,或者用if代替
- 循环
while (n > 0) {
r = r * n
n -=1
}
//Scala中没有for(;;)循环,有2个替代选择:使用while循环,或者使用如下:
for(i <- 1 to n)
r = r * i
- until返回一个不包含上限的区间
val s = "hello"
var sum = 0
for (i <- 0 until s.length)
sum += s(i)
- Scala没有提供break和continue,如果需要,有如下几个方式:
a. 使用Boolean型的控制变量
b. 使用嵌套函数--你可以从函数中return
c. 使用Breaks对象中的break方法:
import scala.util.control.Breaks._
breakable{
for(...){
if(...) break; //退出breakable块,在这里,控制权是通过抛出和捕获异常完成的,因为时间很重要的话,应当避免使用这个套机制(效率低呗)
}
}
- 高级for循环
scala> for (i <- 1 to 3;j <- 1 to 5) print((10*i+j)+" ")
11 12 13 14 15 21 22 23 24 25 31 32 33 34 35
//循环中定义变量
scala> for (i <- 1 to 3;from=4-i;j <- from to 3 if i!=j) print((10*i+j)+" ")
13 23 31 32
scala> for (i <- 1 to 4;from=4-i;j <- from to 3) print((10*i+j)+" ")
13 22 23 31 32 33 40 41 42 43
//for推导式
//如果for循环的循环体以yield开始,则循环会构造出一个集合,每次迭代成成集合中的一个值:
scala> for( i<- 1 to 10) yield i%3
res8: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 0, 1, 2, 0, 1, 2, 0, 1)
注:变量<-表达式叫生成器,,每个生成器可以带一个“守卫”,以if开头Boolean表达式,,from这种叫做定义。也可以不用分号分割,用换行分割:
for { i <- 1 to 3 //生成式
from = 4 -i //定义
j <- from to 3 //生成式 (这种相当于是2次循环,先i[0],匹配所有的j,再i[1]...)
}
- 函数
// 函数名 参数 函数体
def abs(x: Double) = if (x >= 0) x else -x
只要不是递归函数,不需要指定返回值类型,Scala编译器自动推断。
最后一个表达式是函数返回值,不建议使用return。
//递归函数
def fac(n: Int): Int = if (n < 0) 1 else n * fac(n - 1)
2.8 默认参数和带名参数
def decorate(str: String, left: String = "[", right: String = "]") = left + str + right
调用参数可以不按照顺序:
decorate(left = "<<<" ,str = "hello", right = ">>>")
2.9 变长参数
def sum(args: Int*) = {
var result = 0
for (arg <-args) result +=arg
result
}
调用:
val s = sum(1,4,9,16,25) //参数腰围Seq类型
错误调用:
scala> val s = sum(1 to 5)
<console>:12: error: type mismatch;
found : scala.collection.immutable.Range.Inclusive
required: Int
val s = sum(1 to 5)
修改:加上_* 告诉编译器希望这个参数当作参数序列处理
scala> val s = sum(1 to 5:_*)
s: Int = 15
2.10 过程
Scala对于不返回值的函数有特殊的表示法。如果函数体包含再花括号当中但没有前面的=号,那么返回类型就是Unit,这样的函数被称为过程(procedure)。过程不返回值,调用是为了它的副作用。如:
def box(s: String) {
println(s+ "|")
}
//有人建议总是显式声明Unit返回值类型:
def box(s: String): Unit = {
println(s+ "|")
}
2.11 懒值
当val被声明为lazy时,初始化将被推迟,直到首次对他取值。
scala> lazy val words = scala.io.Source.fromFile("c://errlog.txt").mkString
words: String = <lazy>
//在words被首次使用时取值(这里文件不存在也不会报错,使用时报错)
scala> lazy val words = scala.io.Source.fromFile("c://errlog.tx1t").mkString
words: String = <lazy>
scala> words
java.io.FileNotFoundException: c:\errlog.tx1t (系统找不到指定的文件。)
...
//在每一次words被使用时取值
scala> def words = scala.io.Source.fromFile("c://errlog.txt1").mkString
words: String
scala> words
java.io.FileNotFoundException: c:\errlog.txt1 (系统找不到指定的文件。)
...
2.12 异常
抛出的对象必须是java.lang.Throwable的子类。
Scala没有“受检”异常–不需要声明函数或者方法可能跑出某种异常
受检异常在编译期被检查,比如,需要再方法做出声明:
void Something() throws IOException.
thow表达式有特殊的类型Nothing,再if/else表达式中很有用。
if (x >= 0) {
sqrt(x)
} else
throw new IllegalArgumentException("x should not be negative")
//第一个分支类型是Double,第二个分支类型是Nothing,因此if/else表达式类型是Double。
捕获异常采用模式匹配语法:
try{
process(new URL("http://*****"))
} catch {
case _: MalformedURLException => println("Bad URL:" + url)
case ex :IOException => ex.printStackTrace()
}
3.数组相关操作[ ⬆TOP](#start)
3.1 定长数组
scala> val nums = new Array[Int](10)//在JVM中Scala中Array以Java数组方式实现,这个对应JVM中就是个int[]
nums: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
scala> val a = new Array[String](10)
a: Array[String] = Array(null, null, null, null, null, null, null, null, null, null)
scala> val s = new Array("hello","world") //已提供初始值的不需要new
<console>:11: error: too many arguments for constructor Array: (_length: Int)Array[T]
val s = new Array("hello","world")
^
scala> val s = Array("hello","world")
s: Array[String] = Array(hello, world)
scala> s(0) //使用()来访问,而不是[]
res15: String = hello
scala> s(0) = "goodbye"
scala> s
res17: Array[String] = Array(goodbye, world)
scala>
3.2 变长数组:数组缓冲
相当于java中ArrayList
scala> import scala.collection.mutable.Array
ArrayBuffer ArrayBuilder ArrayLike ArrayOps ArraySeq ArrayStack
scala> import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.ArrayBuffer
scala> val b = ArrayBuffer[Int]() //或者val b = new ArrayBuffer[Int]
b: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
scala> b += 1
res18: b.type = ArrayBuffer(1)
scala> b += (1,2,3,5) //++=追加任何集合
res19: b.type = ArrayBuffer(1, 1, 2, 3, 5)
scala> b ++= Array(8,13,21)
res20: b.type = ArrayBuffer(1, 1, 2, 3, 5, 8, 13, 21)
scala> b.trim
trimEnd trimStart
scala> b.trimEnd(5) //移除最后5个元素
scala> b
res23: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 1, 2)
b.insert(2,6) //再下标2位置插入
b.insert(2,1,2,2,0) //在下标2之前插入多个元素
b.remove(2)//移除下标为2元素
b.remove(2,3)//移除下标为2开始3个元素
b.toArray //a.toBuffer 缓冲数组和数组的转换
3.3 遍历数组和数组缓冲
for (i <- 0 until a.length ){
println(a(i))
}
for (i <- (0 until a.length).reverse ){
println(i)
}
//如果是直接遍历元素,可以不需要下标:
for(i <- a ) print(i)
3.4 数组转换
scala> val a = Array[Int](2,3,4,5)
a: Array[Int] = Array(2, 3, 4, 5)
scala> val result = for(elem <- a ) yield 2 * elem
result: Array[Int] = Array(4, 6, 8, 10) //如果a是ArrayBuffer这里也是ArrayBuffer。这里result是一个新的数组,对a没有影响
3.4 常用算法
scala> val a = Array(2,9,4,3)
a: Array[Int] = Array(2, 9, 4, 3)
scala> a.max
res34: Int = 9
scala> a.sum
res35: Int = 18
scala> a.min
res36: Int = 2
scala> a.sorted //排序
res37: Array[Int] = Array(2, 3, 4, 9)
scala> a.sortWith(_>_)
res38: Array[Int] = Array(9, 4, 3, 2)
scala> scala.util.Sorting.quickSort(a) //直接修改了a,a不能是缓冲数组
scala> a
res40: Array[Int] = Array(2, 3, 4, 9)
scala> a.mkString
res41: String = 2349
scala> a.mkString(" and ")
res42: String = 2 and 3 and 4 and 9
scala> a.mkString("<",",",">")
res43: String = <2,3,4,9>
4.映射和元组[ ⬆TOP](#start)
4.1 操作
scala> val a = Array("a","b","c")
a: Array[String] = Array(a, b, c)
scala> val b = Array(1,2,3)
b: Array[Int] = Array(1, 2, 3)
scala> val pairs = a zip b //拉链操作,个数要一致
pairs: Array[(String, Int)] = Array((a,1), (b,2), (c,3))
scala> for((k,v) <- pairs) print(k,v)
(a,1)(b,2)(c,3)
scala> val map = pairs.toMap //集合转map
map: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2, c -> 3)
scala> map.getOrElse("fff",100)
res58: Int = 100
//可变Map:scala.collection.mmutable.Map
//不可变Map:scala.collection.immutable.Map(默认是不可变Map)
//创建一个空的映射:
scala> val scores = new scala.collection.mutable.HashMap[String,Int]
scores: scala.collection.mutable.HashMap[String,Int] = Map()
scala> scores("Bob") = 10 //修改内容,这里报错,因为是不可表映射
//可通过这种方法修改,直接等于自己会报错如val scores = scores报错
val scores2 = scores + ("Bob" ->10 ,"Fred" -> 7)
4.6 与java的互操作
//只需要引入对应转换语句:
scala> import scala.collection.JavaConversions.
!= asScalaBuffer getClass ne
## asScalaIterator hashCode notify
+ asScalaSet isInstanceOf notifyAll
-> bufferAsJavaList iterableAsScalaIterable propertiesAsScalaMap
== collectionAsScalaIterable mapAsJavaConcurrentMap seqAsJavaList
asInstanceOf dictionaryAsScalaMap mapAsJavaMap setAsJavaSet
asJavaCollection ensuring mapAsScalaConcurrentMap synchronized
asJavaDictionary enumerationAsScalaIterator mapAsScalaMap toString
asJavaEnumeration eq mutableMapAsJavaMap wait
asJavaIterable equals mutableSeqAsJavaList →
asJavaIterator formatted mutableSetAsJavaSet
//java中TreeMap转Scala中Map
scala> import scala.collection.JavaConversions.mapAsScalaMap
val scores : scala.collection.mutable.Map[String,Int] = new java.util.TreeMap[String,Int]
//java中java.util.properties转Map
import scala.collection.JavaConversions.propertiesAsScalaMap
val props : scala.collection.Map[String,String] = System.getProperties()
4.7 元组
scala> val t = (1,3.14,"Fred")
t: (Int, Double, String) = (1,3.14,Fred)
scala> val second = t._2 //元组下标从1开始,而不是0
second: Double = 3.14
scala> t _2 //也可以用这种方式来访问,中间空格
warning: there was one feature warning; re-run with -feature for details
res67: Double = 3.14
scala> val (first,second,third) = t //直接映射结果
first: Int = 1
second: Double = 3.14
third: String = Fred
scala> val (first, second, _) = t //可能你只需要映射2个值
first: Int = 1
second: Double = 3.14