Scala知识点总结

Scala简介

Scala 语言是一个完全面向对象编程语言。万物皆对象 。对象的本质:对数据和行为的一个封装

Scala 语言是一个完全函数式编程语言。万物皆函数。 函数的本质:函数可以当做一个值进行传递

Scala中的变量和常量

var 变量名 [: 变量类型] = 初始值  var i:Int = 10

val 常量名 [: 常量类型] = 初始值  val j:Int = 20

(1)声明变量时,类型可以省略,编译器自动推导,即类型推导

(2)类型确定后,就不能修改,说明 Scala 是强数据类型语言。

(3)变量声明时,必须要有初始值

(4)在声明/定义一个变量时,可以使用 var 或者 val 来修饰,var 修饰的变量可改变, val 修饰的变量不可改。

Scala中的数据类型

Scala中的数值类型自动转换

 

当 Scala 程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数值类型,这 个就是自动类型转换(隐式转换)。数据类型按精度(容量)大小排序为:

 

(1)自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成 精度大的那种数据类型,然后再进行计算。

(2)把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动 类型转换。

(3)(byte,short)和 char 之间不会相互自动转换。

(4)byte,short,char 他们三者可以计算,在计算时首先转换为 int 类型。

Scala中的循环

//i 将会从 1-3 循环,前后闭合
for(i <- 1 to 3){
 print(i + " ")
}
println()
//前闭后开
for(i <- 1 until 3) {
 print(i + " ")
}
println()
//循环守卫,即循环保护式(也称条件判断式,守卫)。保护式为 true 则进入循环体内部,为 false 则跳过,类似于 continue。
for(i <- 1 to 3 if i != 2) {
 print(i + " ")
}
println()
//循环步长
for (i <- 1 to 10 by 2) {
 println("i=" + i)
}
//嵌套循环
for(i <- 1 to 3; j <- 1 to 3) {
 println(" i =" + i + " j = " + j)
}
//引入变量
for(i <- 1 to 3; j = 4 - i) {
 println("i=" + i + " j=" + j)
}
//循环返回值,将遍历过程中处理的结果返回到一个新 Vector 集合中,使用 yield 关键字。
val res = for(i <- 1 to 10) yield i
println(res)
//循环倒序
for(i <- 1 to 10 reverse){
 println(i)
}
//打破循环
import scala.util.control.Breaks._
object TestBreak {
 def main(args: Array[String]): Unit = {
 
 breakable {
  for (elem <- 1 to 10) {
    println(elem)
    if (elem == 5) break
  }
 }
 
 println("正常结束循环")
 }
}
//While 和 do..While 的使用和 Java 语言中用法相同,没有返回值

Scala的尾递归

正常得递归,每一次递归步骤,需要保存信息到堆栈中去,当递归步骤很多的时候,就会导致内存溢出

而尾递归,就是为了解决上述的问题,在尾递归中所有的计算都是在递归之前调用,编译器可以利用这个属性避免堆栈错误,尾递归的调用可以使信息不插入堆栈,从而优化尾递归

Scala中的函数

object TestFunctionDeclare {
 def main(args: Array[String]): Unit = {
 // 函数 1:无参,无返回值
 def test1(): Unit ={
     println("无参,无返回值")
 }
 test1()
 // 函数 2:无参,有返回值
 def test2():String={
     return "无参,有返回值"
 }
 println(test2())
 // 函数 3:有参,无返回值
 def test3(s:String):Unit={
     println(s)
 }
 test3("jinlian")
 // 函数 4:有参,有返回值
 def test4(s:String):String={
     return s+"有参,有返回值"
 }
 println(test4("hello "))
 // 函数 5:多参,无返回值
 def test5(name:String, age:Int):Unit={
     println(s"$name, $age")
 }
 test5("dalang",40)
 }
}
//可变参数
def test2( name : String, s: String* ): Unit = {
    println(name + "," + s)
}
//参数默认值
def test3( name : String, age : Int = 30 ): Unit = {
    println(s"$name, $age")
}

Scala中函数的高阶用法

1)匿名函数

没有名字的函数就是匿名函数。

(x:Int)=>{函数体}

x:表示输入参数类型;Int:表示输入参数类型;函数体:表示具体代码逻辑

2)函数可以作为值进行传递

object TestFunction {
  def main(args: Array[String]): Unit = {
    //(1)调用 foo 函数,把返回值给变量 f
    val f = foo
    println(f)
    //(2)在被调用函数 foo 后面加上 _,相当于把函数 foo 当成一个整体,传递给变量 f1
    val f1 = foo _
    foo()
    f1()
    //(3)如果明确变量类型,那么不使用下划线也可以将函数作为整体传递给变量
    var f2:()=>Int = foo 
  }
  def foo():Int = {
    println("foo...")
    1
  }
}

3)函数可以作为参数进行传递

def main(args: Array[String]): Unit = {
    //(1)定义一个函数,函数参数还是一个函数签名;f 表示函数名称;(Int,Int)表示输入两个 Int 参数;Int 表示函数返回值
    def f1(f: (Int, Int) => Int): Int = {
        f(2, 4)
    }
 
    // (2)定义一个函数,参数和返回值类型和 f1 的输入参数一致
    def add(a: Int, b: Int): Int = a + b
 
    // (3)将 add 函数作为参数传递给 f1 函数,如果能够推断出来不是调用,_可以省略
    println(f1(add))
    println(f1(add _))
    //可以传递匿名函数
}

4)函数可以作为函数返回值返回

def main(args: Array[String]): Unit = {
    def f1() = {
        def f2() = {
        }
        f2 _
    }
    val f = f1()
    // 因为 f1 函数的返回值依然为函数,所以可以变量 f 可以作为函数继续调用
    f()
    // 上面的代码可以简化为
    f1()()
}        

Scala中的函数柯里化&闭包

闭包:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的 环境,称为闭包

函数柯里化:把一个参数列表的多个参数,变成多个参数列表。

Scala中的控制抽象

1)值调用:把计算后的值传递过去

2)名调用:把代码传递过去

Scala中的惰性加载

当函数返回值被声明为 lazy 时,函数的执行将被推迟,直到我们首次对此取值,该函 数才会执行。这种函数我们称之为惰性函数。

注意:lazy 不能修饰 var 类型的变量

Scala中面向对象

class 类名(形参列表) { // 主构造器
     // 类体
    def this(形参列表) { // 辅助构造器
    }
    def this(形参列表) { //辅助构造器可以有多个...
    }
}

Scala 类的主构造器函数的形参包括三种类型:未用任何修饰、var 修饰、val 修饰

(1)未用任何修饰符修饰,这个参数就是一个局部变量

(2)var 修饰参数,作为类的成员属性使用,可以修改

(3)val 修饰参数,作为类只读属性使用,不能修改

单例对象(伴生对象)

Scala语言是完全面向对象的语言,所以并没有静态的操作(即在Scala中没有静态的概 念)。但是为了能够和Java语言交互(因为Java中有静态概念),就产生了一种特殊的对象 来模拟类对象,该对象为单例对象。若单例对象名与类名一致,则称该单例对象这个类的伴 生对象,这个类的所有“静态”内容都可以放置在它的伴生对象中声明。

object Person{
    val country:String="China"
}

(1)单例对象采用 object 关键字声明

(2)单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。

(3)单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。

apply 方法

(1)通过伴生对象的 apply 方法,实现不使用 new 方法创建对象。

(2)如果想让主构造器变成私有的,可以在()之前加上 private。

(3)apply 方法可以重载。

(4)Scala 中 obj(arg)的语句实际是在调用该对象的 apply 方法,即 obj.apply(arg)。用 以统一面向对象编程和函数式编程的风格。

(5)当使用 new 关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构 建对象时,调用的其实时伴生对象的 apply 方法。

特质(Trait)

Scala 语言中,采用特质 trait(特征)来代替接口的概念,也就是说,多个类具有相同 的特质(特征)时,就可以将这个特质(特征)独立出来,采用关键字 trait 声明。

Scala 中的 trait 中即可以有抽象属性和方法,也可以有具体的属性和方法,一个类可 以混入(mixin)多个特质。这种感觉类似于 Java 中的抽象类。

Scala 引入 trait 特征,第一可以替代 Java 的接口,第二个也是对单继承机制的一种 补充。

trait PersonTrait {
 // 声明属性
 var name:String = _
 // 声明方法
 def eat():Unit={
 }
 // 抽象属性
 var age:Int
 
 // 抽象方法
 def say():Unit
}

一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素, 所以在使用时,也采用了 extends 关键字,如果有多个特质或存在父类,那么需要采用 with 关键字连接。

(1)特质可以同时拥有抽象方法和具体方法

(2)一个类可以混入(mixin)多个特质

(3)所有的 Java 接口都可以当做 Scala 特质使用

(4)动态混入:可灵活的扩展类的功能

(4.1)动态混入:创建对象时混入 trait,而无需使类混入该 trait

(4.2)如果混入的 trait 中有未实现的方法,则需要实现

特质叠加

将混入的多个 trait 中的冲突方法叠加起来

 

特质和抽象类的区别

1.优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。

2.如果你需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数, 而特质不行(有无参构造)。

Scala中的集合

1)Scala 的集合有三大类:序列 Seq、集 Set、映射 Map,所有的集合都扩展自 Iterable 特质。

2)对于几乎所有的集合类,Scala 都同时提供了可变和不可变的版本,分别位于以下两 个包 不可变集合:scala.collection.immutable 可变集合: scala.collection.mutable

3)Scala 不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而 不会对原对象进行修改。类似于 java 中的 String 对象

4)可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似 于 java 中 StringBuilder 对象

集合有各自的基本函数、有公共的基本属性和基本函数、有简单计算函数、有高级计算函数

高级计算函数:filter、map、flatten、flatMap、groupBy、reduce、reduceLeft、reduceRight、fold、foldLeft、foldRight

Scala中的模式匹配

模式匹配语法中,采用 match 关键字声明,每个分支采用 case 关键字进行声明,当需 要匹配时,会从第一个 case 分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹 配不成功,继续执行下一个分支进行判断。如果所有 case 都不匹配,那么会执行 case _分支, 类似于 Java 中 default 语句。如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫。

匹配常量、匹配类型、 匹配数组、匹配列表、匹配元组、匹配对象及样例类(unapply)、变量声明中的模式匹配、for 表达式中的模式匹配

Scala中的隐式转换

当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用 于将类型进行转换,实现二次编译

隐式函数、隐式参数、隐式类

Scala中可以省略的地方

1)当调用对象的方法时,点.可以省略

2)如果函数参数只有一个,或者没有参数,()可以省略

3) return 可以省略,Scala 会使用函数体的最后一行代码作为返回值

4)如果函数体只有一行代码,可以省略花括号

5)返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)

6)如果有 return,则不能省略返回值类型,必须指定

7)如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用

8)Scala 如果期望是无返回值类型,可以省略等号

9)如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加

10)如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略

11)如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略

12)匿名函数:参数的类型可以省略,会根据形参进行自动的推导

13)匿名函数:类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参 数超过 1 的永远不能省略圆括号。

14)匿名函数:匿名函数如果只有一行,则大括号也可以省略

15)匿名函数:如果参数只出现一次,则参数省略且后面参数可以用_代替

Scala和java的区别

1)Scala==更加类似于 Java 中的 equals,参照 jd 工具;eq()比较两个变量本身的值

2)Scala 中 if else 表达式其实是有返回值的,具体返回值取决于满足条件的 代码体的最后一行内容。

3) Scala 中没有++、--操作符,可以通过+=、-=来实现同样的效果;

4) 在 Scala 中没有 Switch,而是使用模式匹配来处理。

5) Scala 中函数可以嵌套定义

6)Scala 中属性和方法的默认访问权限为 public,但 Scala 中无 public 关键字;private 为私有权限,只在类的内部和伴生对象中可用;protected 为受保护权限,Scala 中受保护权限比 Java 中更严格,同类、子类可以 访问,同包无法访问;private[包名]增加包访问权限,包名下的其他类也可以使用

7)Scala 中属性和方法都是动态绑定,而 Java 中只有方法为动态绑定。

8)Scala 的异常的工作机制和 Java 一样,但是 Scala 没有“checked(编译期)”异常, 即 Scala 没有编译异常这个概念,异常都是在运行的时候捕获处理。


 

posted @ 2022-04-26 14:25  1243741754  阅读(178)  评论(0编辑  收藏  举报