scala整理知识点

基本介绍:

起源:

将函数式编程语言的特点融合到Java中,由此发明了Scala。
更简洁、更灵活。

语言特点:

Scala是一门以 JVM 为运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言。
Scala源代码会被编译成Java字节码,然后运行于JVM之上,并可以调用现有的Java类库,实现两种语言的无缝互操作的。
面向对象
    Scala是一种面向对象的语言。
    Scala中的每个值都是一个对象,包括基本数据类型(即布尔值、数字等)在内,连函数也是对象。
函数式编程
    Scala也是一种函数式语言,其函数也能当成值来使用。
    Scala中支持高阶函数,允许嵌套多层函数,并支持柯里化。
    Scala提供了模式匹配,可以匹配各种情况,比如变量的类型、集合的元素、有值或无值。
静态类型
    Scala具备类型系统,通过编译时检查,保证代码的安全性和一致性。
并发性
    Scala使用Actor作为其并发模型,Actor是类似线程的实体。
    Actor可以复用线程,因此可以在程序中使用数百万个Actor,而线程只能创建数千个。

基础语法:

规则:

1.区分大小写 - Scala语言对大小写敏感;
2.类名 - 对于所有的类名的第一个字母要大写。如果需要使用几个单词来构成一个类名,每个单词的第一个字母要大写;比如:ListDemo
3.方法名 - 所有方法名的第一个字母用小写。如果需要使用几个单词来构成方法名,除第一个单词外每个词的第一个字母应大写;比如:getResult
4.程序文件名 - Scala程序文件的后缀名是 .scala,程序文件的名称可以不与对象名称完全匹配。这点与Java有所区别。
    备注:建议遵循 Java 的惯例,程序文件名称与对象名称匹配;
5.main()方法 - Scala程序从main()方法开始处理,这是每一个Scala程序的入口点。main()定义在object中;
标识符
    所有Scala组件都需要名称,用于对象、类、变量和方法的名称称为标识符。
    关键字不能用作标识符,标识符区分大小写;
注释
    Scala使用了与Java相同的单行和多行注释;
换行符
    Scala语句可以用分号作为一行的结束,语句末尾的分号通常可以省略,但是如果一行里有多个语句那么分号是必须的。

数据类型:

值类型:

(这些类型都是类,有自己的属性和方法)
Byte     8位有符号补码整数。数值区间为 -128 到 127
Short     16位有符号补码整数。数值区间为 -32768 到 32767
Int     32位有符号补码整数。数值区间为 -2147483648 到 2147483647
Long     64位有符号补码整数。数值区间为 -9223372036854775808 到9223372036854775807
Float     32 位, IEEE 754标准的单精度浮点数
Double     64 位 IEEE 754标准的双精度浮点数
Char     16位无符号Unicode字符, 区间值为 U+0000 到 U+FFFF
Boolean truefalse

引用类型:

String     字符序列
Unit    表示无值,相当于Java中的void,用于不返回任何结果的方法的返回类型。Unit写成()
Null     通常写成null
Nothing Nothing类型在Scala类层级的最低端,它是任何其他类型的子类型
Any     Any是Scala中所有类的超类
AnyRef     AnyRef是Scala中所有引用类的超类

Rich类型:

每一种数据类型都有对应的Rich类型,如RichInt、RichChar等,为基本类型提供了更多的有用操作。

字面量:

与JAVA基本相同
整数字面量
    val magic = 0xcafeL
    val littler: Byte = 127
浮点数字面量
    val bigger = 3.1415926e1
    val litte = 0.31415926e1F   float
字符字面量
    val a = 'A'     char
    val b = '\u0042'            
    val mark = '\\' 转义
字符串字面量
    val str = "Hello Scala"

类层次结构:

值类型和引用类型,都最终继承自一个统一的根类型Any。
Any是所有类型共同的根类型,Any是AnyRef和AnyVal的超类
AnyRef是所有引用类型的超类
AnyVal是所有值类型的超类
Null是所有引用类型的子类型,Null类只有一个实例对象nullnull可以赋值给任意引用类型,但是不能赋值给值类型。
Nothing位于Scala类继承关系的底部,它是其他所有其他类型的子类型。
Unit类型用来标识过程,过程就是没有返回值的方法,Unit类似于Java里的void。Unit只有一个实例()。
None是一个object,是Option的子类型,用于match case匹配
Nil是一个空的List,定义为List[Nothing],根据List的定义List[+A],所有Nil是所有List[T]的子类。

值与变量:

Scala当中的声明变量可以使用以下两种方式:

val,值 -- value,用val定义的变量,值是不可变的
var,变量 -- variable,用var定义的变量,值是可变的
在Scala中,鼓励使用val。大多数程序并不需要那么多的var变量。
声明变量时,可以将多个变量放在一起声明。

自动类型推断:

声明变量时,可以不指定变量的数据类型,编译器会根据赋值内容自动推断当前变量的数据类型。
备注:简单数据类型可以省略,对于复杂的数据类型建议明确声明;

操作符:

Scala的算术操作符、位操作符与 Java中的效果一样的。
需要特别注意一点:Scala中的操作符都是方法
例如a + b 等价 a.+(b),1 to 10 等价 1.to(10)

Scala 没有提供 ++、-- 操作符,但是可以使用+=、-=

块表达式
{} 块包含一系列表达式,其结果也是一个表达式,块中最后一个表达式的值就是块的值。

赋值语句
赋值语句返回Unit类型,代表没有值;

字符串插值器
s 插值器,对内嵌的每个表达式求值,对求值结果调用toString,替换掉字面量中的那些表达式
    示例:val str2 = s"arr.length = ${arr.length}"
f 插值器,它除s插值器的功能外,还能进行格式化输出,在变量后用%指定输出格式,使用java.util.Formatter中给出的语法
    示例:println(f"$year-$month%02d-$day%02d")
raw 插值器,按照字符串原样进行输
    示例:println(raw"a\nb\tc"),等价于println("""a\nb\tc""")

对象相等性
Java 中可以 == 来比较基本类型和引用类型:
    对基本类型而言,比较的是值的相等性
    对引用类型而言,比较的是引用相等性,即两个变量是否指向JVM堆上的同个对象

控制结构:

if表达式:

概述:

Scala中 if 表达式有返回值。
如果if 和 else 的返回值类型不一样,那么就返回两个返回值类型公共的父类。

语法:

if(x<1) 表达式,缺省 else 语句返回unit实例()
if(x<1) 表达式 else if() 表达式 else 表达式

for表达式:

语法:

for (i <- 表达式/集合){代码块}

示例:

for (i <- 1 to 10)
for (i <- 1 until 10)
for (i <- 1 until 5; j <- 2 until 5) 双重循环。条件之间使用分号分隔,每个i遍历一次j
for (i <- 1 to 3 ;j = 4-i)每次循环赋值一次变量
for (i <- 1 to 10; j <- 1 to 10 if i==j)守卫语句。仅当if条件成立时执行代码块
val result = for (i <- 1 to 10) yield i使用 yield 接收返回的结果,最后整个表达式返回列表。这种形式被称为for推导式

while表达式:

与 Java 类似的whiledo...while循环
Scala内置控制结构特地去掉了 break 和 continue
特殊情况下如果需要终止循环,可以有以下三种方式:
    使用Boolean类型的控制变量
    使用return关键字
    使用breakable和break,需要导入scala.util.control.Breaks包

函数:

格式:

def funtion(x:int,y:int):Int={
    if(x>y)
        x
    else
        y 
}

概述:

函数体中最后一句为返回值的话,可以将return 去掉;
如果一个函数体只有一句代码,大括号可以去掉;
可以不声明函数的返回类型,返回类型可通过自动类型推断来完成,但递归函数的返回类型必须声明;

过程:

如果一个函数没有返回值,其返回类型为Unit(省略掉), 并且 “=” 号可以去掉,这样的函数被称为过程;
def funtion(x:int,y:int){}
参数的默认值
def funtion(x:int=12,y:int=20)
变长参数
def add(x: Int*)
只能位于最后一位,一个函数只能有一个。
懒值
当 val 被声明为lazy时(var不能声明为lazy),它的初始化将被推迟,直到首次对此取值,适用于初始化开销较大的场景。
lazy val file2 = scala.io.Source.fromFile("src/test111.scala")

文件操作:

概述:

导入scala.io.Source后,可引用Source中的方法读取文本文件的内容

打开文件:

val file: BufferedSource = Source.fromFile("... ...""GBK")

读取内容:

val lines: Iterator[String] = file.getLines()
写入
val writer = new PrintWriter("../a.txt")
writer.println(i)

数组:

概述:

定长数组Array
不定长数组ArrayBuffer

定长数组:

声明:

val nums = new Array[Int](10)        元素的值为默认值,0.
val arrays = Array(1, 2, 3)
val b = ArrayBuffer[Int]()

索引:

nums(9) = 10
变长数组

声明:

导包 import scala.collection.mutable.ArrayBuffer
val nums = ArrayBuffer[Int]()

操作:

nums += 1            // 在尾端添加元素
nums += (2,3,4,5)    // 在尾端添加多个元素
nums ++= Array(6,7,8)// 使用++=在尾端添加任何集合
nums.append(1)        // 使用append追加一个或者多个元素
nums.append(2,3)
nums.insert(2,20)    // 在下标2之前插入元素
nums.trimEnd(2)        // 移除最后2元素
nums.trimStart(1)    // 移除最开始的一个或者多个元素
nums.remove(2[,n])    // 从下标2处移除一个或者多个元素
数组转换        
val arrayArray[Int]=nums.toArray
val arrayBuffer: mutable.Buffer[Int]=array.toBuffer
数组遍历
for (i <- 0 until nums.length)
for (i <- 0 to nums.length-1)
for (elem <- nums)

转换操作(适合数组、list):

概述:

这些转换动作不会修改原始数组,而是产生一个全新的数组。

常见:

a1.head
a1.last
a1.tail    // 除了第一个元素,剩下的其他元素
a1.init    // 除了最后一个元素,剩下其他元素
a1.sum
a1.product元素相乘
a1.max
a1.min
a1.sorted
a1.sorted.reverse
a1.sortWith(f)
a1.map(f)
a1.reduce(f)
a1.distinct
a1.length
a1.size
a1.indices
a1.count(f)
a1.filter(f)
a1.filterNot(f)
a1.toString
a1.mkString(" & ")
a1.mkString("<"" & "">")
a1.toBuffer
a1.take(n)取前n个元素原始数组中的数据保持不变,返回一个新的数组
a1.takeRight(4)
a1.takeWhile(f)takeWhile 从左向右提取列表的元素,直到条件不成立(条件不成立时终止)
a1.drop(n)    删除前n个元素
a1.dropRight(n)    删除前n个元素
a1.dropWhile(f)    删除前n个元素
a1.splitAt(index)    分为两部分,从index开始
a1.slice(2,5)    
a1.zip(a2)
a1.zipAll(a2, "*"-1)拉链操作;a1,a2的长度不一致时,a1用 * 填充,a2用 -1 填充
a1.a1.zipWithIndex用数组索引号填充
z4.unzip拆分成n个数组
用于数组的操作符(:+、+:、++)
    :+ 方法用于在尾部追加元素;
    +: 方法用于在头部追加元素;冒号永远靠近集合类型,加号位置决定元素加在前还是后;
    ++ 该方法用于连接两个集合(数组、列表等),arr1 ++ arr2;
多维数组        
通过Array的ofDim方法来定义一个多维的数组    

示例:

val dim = Array.ofDim[Double](3,4)

元组:

概述:

元组是不同类型的值的集合,元组中的元素可以是不同的数据类型,元组在Scala中的应用非常广泛。
对偶是元组的最简单形态;
元组的元素个数上限是22个

定义:

val a = (11.2"ad"'d')
val b = Tuple4(11.2"ad"'d')

索引:

Tuple的访问形式比较特殊。元组的下标从1开始
a._1
a _2
遍历
for(x <- a.productIterator){}
a.productIterator.foreach(x => println(x))

类与对象:

类:

概述:

在Scala中,类并不用声明为public;
Scala源文件中可以包含多个类,所有这些类都具有公有可见性;
val修饰的变量(常量),值不能改变,只提供getter方法,没有setter方法;
var修饰的变量,值可以改变,对外提供gettersetter方法;
如果没有定义构造器,类会有一个默认的无参构造器;

成员变量:

声明:
1.显示的初始化,然后根据初始化的数据类型自动推断其类型,字段类型可以省略。
    var name = "jacky"
    注意:如果赋值为null,则一定要加数据类型,因为不加类型, 该字段的数据类型就是Null类型
        var address: String = null
2._ 表示一个占位符,编译器会根据变量的数据类型赋予相应的初始值,使用占位符,变量类型必须指定
    var nickName: String = _
    注意:val修饰的变量不能使用占位符
类私有:
类私有字段,有私有的getter方法和setter方法,在类的内部可以访问,其伴生对象也可以访问
private var hobby: String = "旅游"
对象私有
private[thisval cardInfo = "123456"
赋值和获取:
person.age_=(20)//注意:如果使用对象的属性加上 _= 给var修饰的属性进行重新赋值,其实就是调用age_=这个setter方法
person.age = 50
println(person.age)    //直接调用类的属性,其实就是调用getter方法
自定义getter和setter方法
private var _leg = 0        //字段属性名以“_”作为前缀
def leg = _leg
def leg_=(newLeg: Int) {
    _leg = newLeg
}
Bean属性
将Scala字段标注为 @BeanProperty时,getFoo和setFoo方法会自动生成。
    @BeanProperty var name:String = _
使用@BeanProperty并不会影响Scala自己自动生成的getter和setter方法。
在使用时需要导入包scala.beans.BeanProperty

实例化:

val person = new Person()
或者
val person1 = new Person        //创建类的对象时,小括号()可以省略
构造器
默认构造器
    如果没有定义构造器,Scala类中会有一个默认的无参构造器;
分类:
    Scala当中类的构造器分为两种:主构造器和辅助构造器;
主构造器
    与类的定义交织在一起,将主构造器的参数直接放在类名之后。
    当主构造器的参数不用varval修饰时,参数会生成类的私有val成员。
    示例:
        class Dog(name: String, age: Int) {
            println(name)//类中不在任何方法中的代码,都属于主构造器的代码。
            println(age) //创建类的对象时会去执行主构造器的代码。下面的println代码就是主构造器的一部分
        }
辅助构造器
    所有的辅助构造器都必须调用另外一个构造器,另外一个构造器可以是辅助构造器,也可以是主构造器。
    def this(name: String, age: Int, gender: String) {
        this(name, age) //每个辅助构造器,都必须以其他辅助构造器,或者主构造器的调用作为第一句代码
    }

对象object

概述:

Scala并没有提供Java那样的静态方法或静态字段;
可以采用object关键字实现单例对象,具备和Java静态方法同样的功能;
使用object语法结构达到静态方法和静态字段的目的;对象本质上可以拥有类的所有特性,除了不能提供构造器参数;
对于任何在Java中用单例对象的地方,在Scala中都可以用object实现:
    1.作为存放工具函数或常量的地方
    2.高效地共享单个不可变实例

特点:

1、创建单例对象不需要使用new关键字
2、object中只有无参构造器
3、主构造代码块只能执行一次,因为它是单例的
伴生类与伴生对象
概述:
当单例对象与某个类具有相同的名称时,它被称为这个类的“伴生对象”;
类和它的伴生对象必须存在于同一个文件中,而且可以相互访问私有成员(字段和方法)(前提是必须实例化才能访问class,只是可以访问private修饰符)
不通过new,而是类名直接实例化时,调用的是伴生对象的apply方法。
示例:
class ClassObject {
    val id = 1
    private var name = "lagou"
    def printName(): Unit ={
        println(ClassObject.CONSTANT + name )//在ClassObject类中可以访问伴生对象ClassObject的私有字段
    }
}
object ClassObject{
    private val CONSTANT = "汪汪汪"
    def apply(name: String, age: Int): Student = new Student(name, age)//apply方法定义在伴生对象中
    def main(args: Array[String]) {
        val p = new ClassObject
        p.name = "123"//访问伴生类的私有字段name
        p.printName()
    }
}
apply方法
概述: 
    apply方法通常定义在伴生对象中,目的是通过伴生类的构造函数功能,来实现伴生对象的构造函数功能;
    通常我们会在类的伴生对象中定义apply方法(和伴生类主构造方法有相同个数的参数),当遇到类名(参数1,...参数n)时apply方法会被调用;
    在创建伴生对象或伴生类的对象时,通常不会使用new class/class() 的方式,而是直接使用class()隐式的调用伴生对象的 apply 方法,这样会让对象创建的更加简洁;
应用: 
    实现工厂方法,让子类声明哪种对象应该被创建,保持对象创建在同一位置。
    apply方法判断即可
应用程序对象
每个Scala应用程序都必须从一个对象的main方法开始,这个方法的类型为 Array[String] => Unit
除了main方法以外,也可以扩展App特质(trait

如:

object Hello extends App{}

特质:

概述:

首先可以将trait作为接口来使用,此时的trait就与Java中的接口非常类似。
类可以使用extends关键字继承trait。注意:在Scala中没有implement的概念,无论继承类还是trait特质,统一都是extends。

多继承:

Scala不支持对类进行多继承,但是支持多重继承trait特质,使用with关键字即可。
如:class Person(nameString) extends HelloTrait with MakeFriendsTrait with Serializable

抽象方法:

trait中可以定义抽象方法,与抽象类中的抽象方法一样,只要不给出方法的具体实现即可。
类继承trait特质后,必须实现其中的抽象方法,实现时可以省略override关键字。

具体方法:

特质不仅仅可以定义抽象方法,还可以定义具体实现的方法,这时的trait更像是包含了通用工具方法的类。
比如,trait中可以包含一些很多类都通用的功能方法,比如打印日志等等
示例: 
    trait People {
        val name: String    //定义抽象字段,子类需要重写
        def eat(message: String): Unit = {
            println(message)
        }
    }
抽象字段
必须重写
具体字段
多个trait都有相同字段时,必须显示override重写。
构造器
trait特质也是有构造器的,也就是trait中的不包含在任何方法中的代码。

构造顺序:

1、执行父类的构造器;
2、执行trait的构造器,多个trait从左到右依次执行;
3、构造trait时会先构造父trait,如果多个trait继承同一个父trait,则父trait只会构造一次;
4、所有trait构造完毕之后,子类的构造器才执行
特质继承类
    trait特质也可以继承class类,此时这个class类就会成为所有继承此trait的类的父类。
Ordered和Ordering
概述:
在Java中对象的比较有两个接口,分别是Comparable和Comparator。它们之间的区别在于:
实现Comparable接口的类,重写compareTo()方法后,其对象自身就具有了可比较性;
实现Comparator接口的类,重写了compare()方法后,则提供一个第三方比较器,用于比较两个对象。
在Scala中也引入了以上两种比较方法
Ordered特质
概述:
混入Java的Comparable接口,它定义了相同类型间的比较方式
trait Ordered[A] extends Any with java.lang.Comparable[A]{......}
示例:
case class Project(tag:Stringscore:Intextends Ordered[Project] {
    def compare(pro:Project ) = tag.compareTo(pro.tag)
}
Ordering特质
概述:
混入Comparator接口,它是提供第三方比较器,可以自定义多种比较方式,在实际开发中也是使用比较多的,灵活解耦合。
trait Ordering[T] extends Comparator[T] with PartialOrdering[T] with Serializable {......}
示例:
Sorting.quickSort(pairs)(Ordering.by[(String, Int, Int), Int](_._2))
样例类

概述:

case class样例类
case class是多例的,后面要跟构造参数,case object是单例的(object本身是单例的)。
case class样例类中可以添加方法和字段,并且可用于模式匹配。

特点:

主构造函数接收的参数通常不需要显式使用varval修饰,Scala会自动使用val修饰
自动为样例类定义了伴生对象,并提供apply方法,不用new关键字就能够构造出相应的对象
将生成toString、equals、hashCode和copy方法,除非显示的给出这些方法的定义
继承了Product和Serializable这两个特质,也就是说样例类可序列化和可应用Product的方法
模式匹配
class Amount
case class Dollar(value: Double) extends Amount//定义样例类Dollar,继承Amount父类
case class Currency(value: Double, unit: String) extends Amount//定义样例类Currency,继承Amount父类
case object Nothing extends Amount//定义样例对象Nothing,继承Amount父类
amt match {
    case Dollar(value) => println(s"$value")
    case Currency(value, unit) => println(s"Oh noes,I got $unit")
    case Nothing => println("Oh,GOD!")
}

模式匹配:

概述:

Scala没有Java中的switch case,它有一个更加强大的模式匹配机制,可以应用到很多场合。
Scala的模式匹配可以匹配各种情况,比如变量的类型、集合的元素、有值或无值。

语法:

变量 match { case 值 => 代码 }

说明:

模式匹配match case中,只要有一个case分支满足并处理了,就不会继续判断下一个case分支了,不需要使用break语句。
这点与Java不同,Java的switch case需要用break阻止。如果值为下划线,则代表不满足以上所有情况的时候如何处理。

匹配变量的值:

charStr match {
    case '/' => println("匹配上了除号")
    case _ => println("都没有匹配上,我是默认值")//注意:不满足以上所有情况,就执行下面的代码
}

守卫式匹配:

val num = character match {
    case '+' => 1
    case _ if character.equals('*') => 3
    case _ => 4
}

匹配类型:

val r1 = obj match {
    case x: Int => x
    case s: String => s.toInt
    case _: BigInt => Int.MaxValue
    case m: Map[String, Int] => "Map[String, Int]类型的Map集合"
    case m: Map[_, _] => "Map集合"
    case a: Array[Int] => "It's an Array[Int]"
    case a: Array[String] => "It's an Array[String]"
    case a: Array[_] => "It's an array of something other than Int"
    case _ => 0
}

匹配数组:

arr match {
    case Array(0, x, y) => println(x + " " + y)
    case Array(0) => println("only 0")
    case Array(1, _*) => println("1 ...")//匹配数组以1开始作为第一个元素
    case _ => println("something else")
}

匹配列表:

构造List列表的两个基本单位是Nil和::,Nil表示为一个空列表
list match {
    case x :: y :: Nil => println(s"x: $x y: $y"//带有2个数元素的列表
    case 0 :: Nil => println("only 0")  //匹配只有0的列表
    case 1 :: tail => println("1 ...")  //匹配1开头的列表
    case _ => println("something else")
}

匹配元组:

tuple match {
    case (1, x, y) => println(s"1, $x , $y")
    case (_, z, 5) => println(z)
    case _ => println("else")
}

Option:

Option选项类型用来表示一个值是可选的,有值或无值。
Option[T] 是一个类型为 T 的可选值的容器。如果值存在,Option[T] 就是一个 Some。如果不存在,Option[T] 就是对象 None 。
Option通常与模式匹配结合使用,用于判断某个变量是有值还是无值。
示例: 
    val grade = grades.get(name)            //从map中取出来的值为option类型
    grade match {
        case Some(T) => println("成绩:" + T)  //输出some当中的声明变量
        case None => println("没有此人成绩!")
    }

函数:

定义:

val 函数名: 函数类型 = 函数字面量

字面量:

就像变量的“类型”和“值”是分开的两个概念一样,函数的“类型”和“值”也成为两个分开的概念
函数的“值”,就是“函数字面量”。
示例: 
    def add1(x: Int): Int = { x + 1 }
    函数的类型为: (Int) => Int,输入参数列表只有一个括号,可以简写为: Int => Int 
函数类型:
    (输入参数类型列表) => (输出参数类型列表)
    在Scala中有自动类型推断,所以可以省略变量的类型 val 变量名 = 值。
    同样函数也可以这样: val 函数名 = 函数字面量
函数字面量
    把函数定义中的类型声明部分去除,剩下的就是函数的“值”,即函数字面量:
    如(x, y, z) => (x+y, y+z)

函数定义:

val 函数名: 函数类型 = 函数字面量
val 函数名 = 函数字面量
val 函数名 = (参数1:类型1,参数2:类型2) => 函数体

函数与方法的区别:

使用 val 定义的是函数(function),使用 def 定义的是方法(method)。
方法不能作为单独的表达式而存在,而函数可以;
    因为默认输入方法名表示调用,省略了参数。
函数必须要有参数列表,而方法可以没有参数列表;
    函数()
    方法
方法名是方法调用,而函数名只是代表函数对象本身;
在需要函数的地方,如果传递一个方法,会自动把方法转换为函数

匿名函数:

函数没有名字(即字面量)就是匿名函数;又被称为 Lambda 表达式。
语法: 
    (参数名1: 类型1, 参数名2: 类型2, ... ...) => 函数体
使用:
    只有一个参数,小括号可以省略
    使用占位符简化函数字面量
        如x => x + 1简化为_ + 1,注意每个_表示一个占位符,各不相同。

高阶函数:

接收一个或多个函数作为输入 或 输出一个函数。
常用的高阶函数
    map、reduce、flatMap、foreach、filter、count … … (接收函数作为参数)

闭包:

闭包是一种函数,一种比较特殊的函数,在其上下文中引用了自由变量的函数;
    1、闭包是一个函数
    2、函数必须要有返回值
    3、返回值依赖声明在函数外部的一个或多个变量,用Java的话说,就是返回值和定义的全局变量有关

柯里化:

接收多个参数的函数都可以转化为接收单个参数的函数
柯里化函数的定义形式和普通函数类似,区别在于柯里化函数拥有多组参数列表,每组参数用小括号括起来。
示例: 
    def add1(x: Int, y: Int) = x + y
    def add2(x: Int) = (y:Int) => x + y
    def add(x: Int)(y: Int) = x + y     //柯里化函数,第一次调用返回函数

部分应用函数:

部分应用函数是指缺少部分(甚至全部)参数的函数。
示例: 
    def add(x:Int, y:Int, z:Int) = x+y+z
    def addX = add(1_:Int, _:Int)

偏函数:

偏函数(Partial Function)之所以“偏”,原因在于它们并不处理所有可能的输入,而只处理那些能与至少一个 case 语句匹配的输入;
在偏函数中只能使用 case 语句,整个函数必须用大括号包围。
被包裹在大括号中的一组case语句是一个偏函数,是一个并非对所有输入值都有定义的函数;
示例: 
    val pf: PartialFunction[Int, String] = {
        case 1 => "One"
        case 2 => "Two"
        case 3 => "Three"
        case _=> "Other"
    }
    pf(1// 返回: One

隐式机制:

概述:

隐式转换和隐式参数是Scala中两个非常强大的功能,利用隐式转换和隐式参数,可以提供类库,对类库的使用者隐匿掉具体的细节。
要实现隐式转换,只要在程序可见的范围内定义隐式转换函数即可,Scala会自动使用隐式转换函数。

与普通函数的区别:

要以implicit开头,而且最好要定义函数返回类型。

限制:

隐式转换的函数只在当前范围内才有效。如果隐式转换不在当前范围内定义,那么必须通过import语句将其导入

隐式转换函数:

概述:

定义的隐式转换函数,只要在编写的程序内引入,就会被Scala自动使用。
隐式转换函数由Scala自动调用(重点),通常建议将隐式转换函数的名称命名为“one2one”的形式。
将一个对象自动转换为另一个对象,能够调用这个对象的方法。

格式:

implicit def xxx

隐式参数和隐式值:

概述:

在函数定义的时候,支持在最后一组参数中使用 implicit ,表明这是一组隐式参数。在调用该函数的时候,可以不用传递隐式参数,而编译器会自动寻找一个implicit 标记过的合适的值作为参数。

限制:

Scala编译器会在两个范围内查找:
当前作用域内可见的valvar定义隐式变量
隐式参数类型的伴生对象内隐式值

隐式类:

概述:

scala 2.10中新增的用法
其主构造函数可以用作隐式转换,编译器自动发现适合的隐式转换,并自动调用。

示例:

object Test extends App {
  implicit class MyName(xInt) {
    println("im in cons")
    val y = x
  }

  def say(x: MyName) = {
    println(x.y)
  }

  say(5)
}

另一个用法:拓展(函数、方法)功能:

implicit class B(a:A) {
   def show {
       println(a.data)              
   }
}
val a = new A(2)
a.show()
这个时候A会隐身转换为B,能够调用B的方法show
posted @ 2022-01-25 13:46  心平万物顺  阅读(188)  评论(0编辑  收藏  举报