Scala study

书名:Scala 学习手册/(美)Swartz,J. 著;苏金国等译。–北京:中国电力出版社,2016.2

第1章 概述

  1. 输出:println("hello world!"),String 字符为双引号,Char 字符为单引号
  2. REPL:Read,Evaluate,Print,Loop.可以跨会话存储
  3. up 箭头:上一行命令
  4. 每一行的输出resultREPL 会用一个常量变量保存:res0,res1,...
  5. 运行scala文件hello.scala
    1. 交互环境中输入 scala> :load hello.scala
    2. 命令行:scala hello.scala
  6. 退出::q

第2章 数据类型(数值类型:Int,Double,非数值类型:String,Char

  1. 字面量值(不可重新赋值):scala> val x:Int=10,不可变有类型的存储文件,用关键字val(value),类型可省略scala> val x = 10
    Scala study_第1张图片
  2. 变量:scala> var a:Double=2.73,关键字var(variable),类型可省略scala> var a=2.73
  3. 字符串
    val approx = 355/113f
    println("Pi,using 355/113,is about "+approx+".")
    println(s"Pi,using 355/113,is about $approx.")	//内插法
    
  4. 字符串内插(替代格式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.")	//内插法
    
  5. 正则表达式
    "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
    
  6. 类型操作(每个类型都属于一个对象)
    1. scala> 5.asInstanceOf[Double]:val/var 类型转换(尽量用第五条)
    2. scala> nada.getClass:val/var 查看类型
    3. val/var 类型确认:scala> nada.isInstanceOf[Unit]
    4. val/var 散列码: scala> "A".hashCode
    5. val/var 转换函数:toString/toByte/toFloat/...
  7. 元组:包含两个以上值得有序容器,值类型可不同,不可迭代但可通过下标访问。类似关系型数据库中得一行
    // 元组,下标从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=()`,通常用来定义函数和表达式

第3章 表达式 和 条件式

表达式

  1. 表达式:scala> val x=5*20;val amount = x+10,字面量val/var 也是一种表达式

  2. 表达式块:scala> val amount = {val x=5*20;x+10}块中最后一个表达式最为块得返回值。

    1. 表达式块分号,可用换行替代
    2. 表达式块可以嵌套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 !")
    }
    
  3. if…else 表达式块:scala> val max = if(5>3) {val x=4*2;x+2} else 2

  4. 匹配表达式(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!" // 除了通配符,匹配值还可以获取
    }
    
  5. 通配模式匹配

    //值绑定
    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)
    }
    
  6. 模式哨卫匹配(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")
    }
    
  7. 模式变量匹配类型(应该不常用)

循环(表达式的控制结构)

  1. for 循环<-类似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 不换行
    
  2. 迭代器哨卫(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)} //迭代器与迭代器哨卫 分开
    
  3. 嵌套迭代器(多层循环):scala> for {x<-1 to 2;y<-3 to 5}{print(s"($x,$y)")}
  4. 值绑定 for 循环:val powersOf2 = for (i<-0 to 8;pow=1<
  5. while/do…while… 循环
    1. while:scala> var x=10;while (x>=0) x -= 1
    2. do…while:val x=0;do println(s"Here I am,x=$x") while (x>0)

第4章 函数

定义:def multiplier(x:Int,y:Int): Int = {x*y}
函数返回值:一般为表达式块最后一行,也可以使用 return 关键字返回并退出

  1. 过程 procedure:没有返回值的函数
    1. 隐式返回类型:def log(d:Double) = println(f"Got value $d%.2f")
    2. 显示返回类型:def log(d:Double):Unit = println(f"Got value $d%.2f")
  2. 无参函数:def hi():String ="hi"
  3. 块表达式函数:参数为块表达式,可赋 默认值
    def formatEuro(amt:Double = 10) = f" $amt%.2f"
    formatEuro{val rate = 0.011;1500*rate}
    
  4. 递归函数
    1. 递归缺点:栈溢出,调用递归函数太多,耗尽分配的内存
    2. 尾递归特点:不使用额外的栈空间
    // 计算 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)
    }
    
  5. 嵌套函数
    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))	// 局部函数优先于外部函数
    }
    
  6. Vararg 参数
    def mysum(item:Int*):Int = {
    	var total = 0
    	for (i<- item) total += i
    	total
    }
    
    mysum();mysum(20,30)
    
  7. 参数组:def max(x:Int,y:Int) = if(x>y) x else y
  8. 方法和操作符
    1. 函数常存在于对象中,函数更适合的说法通常是方法
    2. Scala 没有任何四则运算符,Scala 使用的算术运算符其实都是实例的方法。这里不使用传统点记法,而是使用空格来分割对象(2)、操作符方法(+)、和方法的参数(3)。例如:2 + 3scala 的操作符记法为2.+(3)
    val d= 65.642
    d.compare(18.0)
    d compare 18.0
    1 + 2 + 3
    (1.+(2)).+(3)
    

第六章 常用数据类型

  1. List:可迭代

    1. filter:List(23,8) filter (_ > 18)
    2. 合并:List(List(1,2),List(3,4)).flatten
    3. 拆分:List(1,2,3,4,5) partition (_<3)
    4. 切片:List(1,2,3,4,5) slice (1,3)
    5. top n:List(1,2,3,4,5) take 3
    6. zip: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)
    
  2. 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 内容增加
    
  3. Cons 操作符

  4. 映射(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)
    
  5. 迭代器(Iterator):基本操作:next(),hasNext

    val iter = Iterator("hadoop","spark")
    while (iter.hasNext){println(iter.next())}
    for (ele <- iter) println(ele)
    
  6. 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)
    }
}

辅助构造器

  1. scala 构造器包含一个主构造器和若干个(>=0)辅助构造器
  2. 辅助构造器名称为 this,每个辅助构造器都必须调用已经定义辅助构造器或主构造器
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)}
}

单例对象 和 伴生对象

  1. 单例对象:对象定义不需要出现class,而是用 object。静态变量,每次调用都累加
  2. 伴生对象
    1. 同时包含实例方法 和 静态方法的类
    2. 当单例对象 与某类具有相同名称时,它被称为这个类的伴生对象
    3. 类及其伴生对象 必须存在于同一文件,可以相互访问
    4. 定义在伴生对象的方法都属于静态方法(static method)
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 反编译

继承

  1. 子类重写超类的抽象方法不需要使用 override 关键字
  2. 只有 主构造器 可以调用 超类中的 主构造器
  3. 可以重写超类中的字段
  4. 重写一个非抽象方法必须使用 override 修饰符
  5. Scala 和 Java 一样,不允许从多个超类中继承
  6. abstract 抽象类关键字,extends 继承关键字
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)
    }
}

你可能感兴趣的:(机器学习)