书名:Scala 学习手册/(美)Swartz,J. 著;苏金国等译。–北京:中国电力出版社,2016.2
println("hello world!")
,String
字符为双引号,Char
字符为单引号result
REPL 会用一个常量变量保存:res0,res1,...
scala
文件hello.scala
scala> :load hello.scala
scala hello.scala
:q
Int,Double
,非数值类型:String,Char
)scala> val x:Int=10
,不可变有类型的存储文件,用关键字val
(value),类型可省略scala> val x = 10
scala> var a:Double=2.73
,关键字var
(variable),类型可省略scala> var a=2.73
val approx = 355/113f
println("Pi,using 355/113,is about "+approx+".")
println(s"Pi,using 355/113,is about $approx.") //内插法
printf
,难读,输出可格式化)val item = "apple"
println(s"How do you like them ${item}s?")
println(s"Fish n chips n ,${"pepper "*3}salt") // 字符串乘法
println(f"I wrote a new $item%.3s today")
println(f"Pi,using 355/113,is about ${355/113.0}%.5f.") //内插法
"Froggy went a' courting" matches ".* courting" //Ture or False
"milk,tea,muck" replaceAll ("m[^ ]+k","coffee")
"milk,tea,muck" replaceAll ("m[^ ].k","coffee")
"milk,tea,muck" replaceFirst ("m[^ ]+k","coffee")
"milk,tea,muck" replaceFirst ("m[^ ].k","coffee")
// 捕获组:小括号定义,输入至少包括一个匹配值
val input = "Enjoy this apple 3.14159 times today"
val pattern = """.* apple ([\d.]+) times .*""".r // r 为字符串操作符
val pattern(amountText) = input
val amount = amountText.toDouble
scala> 5.asInstanceOf[Double]
:val/var 类型转换(尽量用第五条)scala> nada.getClass
:val/var 查看类型scala> nada.isInstanceOf[Unit]
scala> "A".hashCode
toString/toByte/toFloat/...
// 元组,下标从1开始
val info = (5,"Korben",true)
val name = info._2
val red = "red"->"0xff0000" // 利用关系操作符创建2元组
val reversed = red._2 -> red._1
注:
1. 值优先于变量,因为值可以为代码带来稳定性和可预测性。
2. 类型为Double 的变量可以赋 Int 值,因为Int数可以自动转换为Double 数。
3. 变量命名建议:`camel case`驼峰命名
4. 字符串支持三重双引号
5. Scala 不支持其他类型到Boolean 的自动转换,非Null 字符不会计算为True,0也不等于False
6. &&与||很懒,第一个参数可以出结论,不在计算第二个参数。&与| 会对两个参数都做检查
7. Unit 字面量:`scala> val nada=()`,通常用来定义函数和表达式
表达式:scala> val x=5*20;val amount = x+10
,字面量val/var 也是一种表达式
表达式块:scala> val amount = {val x=5*20;x+10}
块中最后一个表达式最为块得返回值。
scala> {val a=1;{val b=a*2;{val c=b+4;c}}}
// 结果可以赋值给变量
val x = -3
if (x>0) {
println("This is a positive number!")
} else if (x==0){
println("This is zero")
} else {
println("This is a negative number !")
}
if…else 表达式块:scala> val max = if(5>3) {val x=4*2;x+2} else 2
匹配表达式(match expressions
):类似 switch
// 匹配表达式
val status=500
val message = status match {
case 200 => "ok"
case 400 => println("ERROR - we called the service incorrectly");"error"
case 500 => {
println("ERROR - the service encountered an error");"error"
}
}
// 模式替换式 pattern alternative
val day = "MON"
val kind = day match {
case "MON"|"tue"|"wed"|"thu"|"fri" => "weekday"
case "sat"|"sun" => "weekend"
case unexpected => unexpected + " is not expected!" // 除了通配符,匹配值还可以获取
}
通配模式匹配
//值绑定
val message="ok"
val status = message match {
case "ok" => 200
case other => println(s"could not parse $other");-1
}//other 为case 块定义,并赋值为 message
//通配符
val message="Tom"
val status = message match {
case "ok" => 200
case _ => println(s"could not parse $message");-1
}//_ 通配符,可以匹配任意值,右侧不可访问.若需要访问,可直接访问输入
// 类型模式
for (elem <- List(9,12.3,"spark","hadoop",'hello)){
println("current value is:",elem)
val result = elem match {
case i:Int => i + " is an int value"
case d:Double => d + " is an double value"
case "spark" => "spark is find"
case s:String => s + " is a string value"
case _ => "this is an unexpected value"
}
println(result)
}
模式哨卫匹配(case 后面 + if 表达式,可不加括号)
val response:String ="ok1"
response match {
case s if s!= null => println(s"Received '$s'")
case s => println("ERROR! Received a null response")
}
模式变量匹配类型(应该不常用)
<-
类似python 中的 in
。(x <- 1 to 7 by 1)
为生成器for (x <- 1 to 7 by 1) {println(s"Day $x")}
println(s"${"*"*3}等价于${"*"*3}")
val week = for (x <- 1 until 8 by 1) yield {s"Day $x:"} //返回值将作为一个集合返回,可迭代,for 推导式
for (day <- week) print(day+",") // print 不换行
iterator guard/filter
,增加一个 if表达式)val threes = for(i<-1 to 20 if i%3==0) yield i
val quote = "Faith,Hope,,Charity,null"
for {t<-quote.split(",");if t!=null;if t.size>0}{println(t)} //迭代器与迭代器哨卫 分开
scala> for {x<-1 to 2;y<-3 to 5}{print(s"($x,$y)")}
val powersOf2 = for (i<-0 to 8;pow=1<
scala> var x=10;while (x>=0) x -= 1
val x=0;do println(s"Here I am,x=$x") while (x>0)
定义:def multiplier(x:Int,y:Int): Int = {x*y}
函数返回值:一般为表达式块最后一行,也可以使用 return 关键字返回并退出
def log(d:Double) = println(f"Got value $d%.2f")
def log(d:Double):Unit = println(f"Got value $d%.2f")
def hi():String ="hi"
def formatEuro(amt:Double = 10) = f" $amt%.2f"
formatEuro{val rate = 0.011;1500*rate}
// 计算 x^n 幂
def powerN(x:Int,n:Int):Double = {
n match {
case n if n<0 => 1.0/x * powerN(x,n+1);
case n if n>=1 => x * powerN(x,n-1);
case n => 1
}
}
// tail-recursion 递归调用函数本身作为返回值,才能由Scala 编译器完成尾递归优化
@annotation.tailrec
def power(x:Int,n:Int,t:Int=1):Int = {
if (n<1) 1
else power(x,n,x*t)
}
def max(a:Int,b:Int,c:Int):Int = {
def max(x:Int,y:Int) = if(x>y) x else y
max(a,max(b,c)) // 局部函数优先于外部函数
}
def mysum(item:Int*):Int = {
var total = 0
for (i<- item) total += i
total
}
mysum();mysum(20,30)
def max(x:Int,y:Int) = if(x>y) x else y
2 + 3
scala 的操作符记法为2.+(3)
val d= 65.642
d.compare(18.0)
d compare 18.0
1 + 2 + 3
(1.+(2)).+(3)
List:可迭代
List(23,8) filter (_ > 18)
List(List(1,2),List(3,4)).flatten
List(1,2,3,4,5) partition (_<3)
List(1,2,3,4,5) slice (1,3)
List(1,2,3,4,5) take 3
List(1,2) zip List("a","b")
val colors = List("red","green","blue")
println(s"The colors value's size head remain is ${colors.size},${colors.head},${colors.tail}")
colors(1) // List 下标从 0 开始
// 高阶函数
colors.foreach((c:String)=>println(c))
val numbers = colors.map((c:String)=> c.size)\
val total_str = colors.reduce((a:String,b:String)=> a+" "+b)
Set
var myset = Set("hadoop","spark") // myset 可以指向不同的地址。Set 默认不可变
myset += "scala" // myset 指向另一个不可变 地址
import Scala.collection.mutable.Set // 可变集合
val myset1 = Set("hadoop","spark")
myset1 += "cloud computing" // myset1 指向地址不变,Set 内容增加
Cons 操作符
映射(Map)
val uni = Map("xmu"->"xiamen uin","thu"->"Tsinghua uin") // 默认不可变
val xmu = if(uni.contains("xmu")) uni("xmu") else 0
println(xmu)
import scala.collection.mutable.Map
val uni = Map("xmu"->"xiamen uin","thu"->"Tsinghua uin") // 可变
uni("xmu") = "xiamen university" // update
uni("fzu") = "fuzhou uni"
uni += ("tju"->"tianjin uni")
uni += ("tju"->"tianjin uni","whu"->"wuhan uni")
for ((k,v) <- uni) printf("code is: %s and name is: %s\n",k,v) // 遍历
for (k <- uni.keys) println(k)
for (k <- uni.values) println(v)
迭代器(Iterator):基本操作:next(),hasNext
val iter = Iterator("hadoop","spark")
while (iter.hasNext){println(iter.next())}
for (ele <- iter) println(ele)
类
else
写入文件:Scala 需要java.io.PrintWriter 实现把数据写入文件
import java.io.PrintWriter
val out = new PrintWriter("/usr/local/output.txt")
for (i <- 0.8f to 1.6f by 0.2f) out.println(i)
out.close()
读取文件:可以使用 Scala.io.Source 的 getLines 方法 实现对文件中所有行读取
import scala.io.Source
val inputFile = Source.fromFile("output.txt")
val lines = inputFile.getLines
for (line <- lines) println(line)
异常处理:Scala 将所有异常都当作 不受检异常,使用 try-catch 结构捕获异常
// 暂不能运行
import java.io.FileReader
import java.io.FileNotFoundException
import java.io.IOException
try {
val f = new FileReader("input.txt")
} catch {
case ex:FileNotFoundException => println("file not found")
case ex:IOException => println("IO error")
case _ => println("else error")
}
finally{
file.close()
}
类
class Counter{
private var value = 0 // 外部不可访问
def increment():Unit = {value += 1}
def current():Int = value
}
val mycounter = new Counter // 无参数可不加括号,下同
println(mycounter.current)
mycounter.increment
println(mycounter.current)
class Counter{
var value = 0 // 外部可访问
def increment(step:Int):Unit = {value += step} // 含参函数
def current():Int = value
}
object Mycounter{
def main(args:Array[String]){
val mycounter = new Counter // 无参数可不加括号,下同
println(mycounter.current)
mycounter.increment(5)
println(mycounter.current)
}
}
getter 与 setter 方法
class Counter{
private var privateValue = 0 // 外部可访问
def value = privateValue // 类似 Java 的 getter 方法
def value_= (newValue:Int){// 类似 Java 的 setter 方法
if (newValue > 0) privateValue = newValue
}
def increment(step:Int):Unit = {value += step} // 含参函数
def current():Int = value
}
object Mycounter{
def main(args:Array[String]){
val mycounter = new Counter
println(mycounter.value)
mycounter.value = 3
println(mycounter.value)
mycounter.increment(5)
println(mycounter.current)
}
}
辅助构造器
class Counter{ // 类 主构造器
private var value = 0 // 计数器起始值
private var name = "" // 计数器名称
private var mode = 1 // 计数器类型
def this(name:String){ // 第一个 辅助构造器,只能调用 主构造器
this() // 调用主构造器
this.name = name
}
def this(name:String,mode:Int){
this(name)
this.mode = mode
}
def increment(step:Int):Unit = {value += step} // 含参函数
def current():Int = value
def info():Unit = {printf("Name:%s and mode is %d\n",name,mode)}
}
object Mycounter{
def main(args:Array[String]){
val mycounter1 = new Counter // 主构造器
val mycounter2 = new Counter("Runner")
val mycounter3 = new Counter("Timer",2)
mycounter1.info
mycounter1.increment(1)
printf("current value is:%d\n",mycounter1.current)
mycounter2.info
mycounter2.increment(2)
printf("current value is:%d\n",mycounter2.current)
mycounter3.info
mycounter3.increment(3)
printf("current value is:%d\n",mycounter3.current)
}
}
class Counter(val name:String,val mode:Int){ // 类:主构造器
private var value = 0 // 计数器起始值
def increment(step:Int):Unit = {value += step} // 含参函数
def current():Int = value
def info():Unit = {printf("Name:%s and mode is %d\n",name,mode)}
}
单例对象 和 伴生对象
class Person {
private val id = Person.newPersonId() // 调用伴生对象(静态 static方法)
private var name = ""
def this(name:String){
this()
this.name = name
}
def info(){printf("The id of %s is %d.\n",name,id)}
}
object Person { // 单例对象:类Person 的伴生对象
private var lastId = 0
private def newPersonId() = {
lastId += 1
lastId
}
def main(args:Array[String]){ // main 函数入口
val person1 = new Person("ziyu")
val person2 = new Person("minxing")
person1.info
person2.info
}
}
scalac hello.scala
scala -classpath . Person
javap Person // Java 反编译
继承
abstract class Car{ // 抽象类:不能被直接实例化
val carBrand :String // 抽象字段:没初始化,必须声明类型
def info() // 抽象方法:没有定义任何方法的方法(空着)
def greeting() {println("welcome to my car!")} // 具体方法
}
class BMWCar extends Car{
override val carBrand = "BMW" // 重写超类字段,必须用 override
def info(){printf("This is a %s car.It is on sale.\n",carBrand)} // 重写超类抽象方法, override 可忽略
override def greeting(){println("welcome to my BMWCar car!")} // 重写超类具体方法, override 不可忽略
}
object Mycar{
def main(args:Array[String]){
val mycar = new BMWCar
mycar.greeting
mycar.info
}
}
特质(trait):继承多个父类
trait CarId{
var id:Int
def currentId():Int
}
trait CarGreeting{
def greeting(msg:String) {println(msg)}
}
class BMWCarId extends CarId with CarGreeting{ // 可以使用多个 with 混入多个特质
override var id:Int = 20000
def currentId():Int = {id += 1;id} // 重写超类抽象方法, override 可忽略
}
object Mycar{
def main(args:Array[String]){
val mycarid = new BMWCarId
mycarid.greeting("welcome my first car!")
printf("my first carid is %d\n",mycarid.currentId)
}
}
函数式编程
// 函数式编程实例 WordCount:对当前目录下文本文件进行词频统计
import java.io.File
import scala.io.Source
object WordCount{
def main(args:Array[String]){
val dirfile = new File("D:/documents/3_linzi_work/com_tools/bailing")
val files = dirfile.listFiles
for (file <- files) println(file)
val listFiles = files.toList
val wordsMap = scala.collection.mutable.Map[String,Int]() // 声明可变映射
listFiles.foreach(
file=>Source.fromFile(file).getLines().foreach(
line=>line.split(" ").foreach(
word=> {
if (wordsMap.contains(word)){
wordsMap(word) += 1
}
else{
wordsMap += (word->1)
}
}
)
)
)
println(wordsMap)
for ((k,v)<- wordsMap) println(k+":"+v)
}
}