SFC2020
SFC2020 管理员

554枚
铜币

689点
威望

0个
银元

Scala学习笔记

2020-06-28 17:09

3900

1.Trait(特质)

Java中提供了接口,允许一个类实现任意数量的接口。在Scala中没有接口的概念,而是提供了“特质(trait)”,它不仅实现了接口的功能,还具备了很多其他的特性。Scala的特质,是代码重用的基本单元,可以同时拥有抽象方法和具体方法。Scala中,一个类只能继承自一个超类,却可以实现多个特质,从而重用特质中的方法和字段,实现了多重继承。

图片:1.png



特质具体方法

图片:2.png



多个特质
object Hello {  
def main(args: Array[String]): Unit = {    
val cBook = new CBook()    
val javaBook = new JavaBook()    
printf("CBookId is %d.\n",cBook.currentId)    
cBook.title("C")    
cBook.info("CBook end.")    
printf("JavaBookId is %d.\n",javaBook.currentId)    
javaBook.title("java")    
javaBook.info("JavaBook end.")  
}
}trait BookId{  
var id: Int  
def currentId(): Int     //定义了一个抽象方法
}
trait BookInfo{  
def info(msg:String){ println(msg) }//定义了一个具体方法
}
trait BookTitle{  
def title(title:String){ println("《"+title+"》") }//定义了一个具体方法
}
class CBook extends BookId with BookInfo with BookTitle { //使用extends关键字继承一个特质 多个with继承多个特质  
override var id = 10000  
def currentId(): Int = {id += 1; id} //返回书编号
}
class JavaBook extends BookId with BookInfo with BookTitle { //使用extends关键字继承一个特质 多个with继承多个特质  
override var id = 20000  
def currentId(): Int = {id += 1; id} //返回书编号
}
/**输出
CBookId is 10001.
《C》
CBookId end.
JavaBookId is 20001.
《java》
JavaBookId end.
**/

2.模式匹配
类似java的switch case

基本示例

图片:3.png



变量代表其他值

图片:4.png



类型模式

图片:5.png



守卫(guard)语句

图片:6.png



for中的模式
for ((k,v) <- 映射) 语句块


case类的匹配

图片:7.png



3.函数定义和高阶函数
函数的类型和值
下面我们一点点引导大家更好地理解函数的“类型”和“值”的概念。

我们现在定义一个大家比较熟悉的传统类型的函数,定义的语法和我们之前介绍过的定义“类中的方法”类似(实际上,定义函数最常用的方法是作为某个对象的成员,这种函数被称为方法):
def counter(value: Int): Int = { value += 1}

上面定义个这个函数的“类型”如下:
(Int) => Int

实际上,只有多个参数时(不同参数之间用逗号隔开),圆括号才是必须的,当参数只有一个时,圆括号可以省略,如下:
Int => Int
上面就得到了函数的“类型”,下面看看如何得到函数的“值”。

实际上,我们只要把函数定义中的类型声明部分去除,剩下的就是函数的“值”,如下:
(value) => {value += 1} //只有一条语句时,大括号可以省略

上面就是函数的“值”,需要注意的是,采用“=>”而不是“=”,这是Scala的语法要求。
现在,我们再按照大家比较熟悉的定义变量的方式,采用Scala语法来定义一个函数,如下:

声明一个变量时,我们采用的形式是:
val num: Int = 5 //当然,Int类型声明也可以省略,因为Scala具有自动推断类型的功能

照葫芦画瓢,我们也可以按照上面类似的形式来定义Scala中的函数:
val counter: Int => Int = { (value) => value += 1 }
从上面可以看出,在Scala中,函数已经是“头等公民”,单独剥离出来了“值”的概念,一个函数“值”就是函数字面量。这样,我们只要在某个需要声明函数的地方声明一个函数类型,在调用的时候传一个对应的函数字面量即可,和使用普通变量一模一样。

匿名函数
我们不需要给每个函数命名,这时就可以使用匿名函数,如下:
(num: Int) => num * 2

上面这种匿名函数的定义形式,我们经常称为“Lambda表达式”。“Lambda表达式”的形式如下:
(参数) => 表达式 //如果参数只有一个,参数的圆括号可以省略
闭包
val addMore=(x:Int)=>x>0
上面就定义了一个普通的函数,在函数中只会应用函数中定义的变量,比如x就是函数的传入参数,不会引用函数外部的变量。而闭包则不同,闭包会引用函数外部的变量,下面是一个闭包定义的实例:
val addMore=(x:Int)=>x+more

可以看出,这个函数定义中,引用了变量more,而more并没有在函数中定义,是一个函数外部的变量。如果这个时候去编译执行这条语句,编译器会报错,因为,more是一个自由变量,还没有绑定具体的值,因此,我们说这个时候这个函数是“开放的”。相对而言,这时的x就是一个绑定的变量,已经在函数中给出了明确的定义。因此,为了能够让addMore正常得到结果,不报错,必须在函数外部给出more的值,如下:

图片:8.png



从上面代码可以看出,我们给more确定具体的值1以后,就让函数addMore中的more变量绑定了具体的值1,不再是“自由变量”,而是被绑定具体的值了,或者说“被关闭”了,这也是为什么我们说这样一个函数叫做“闭包”,它反映了一个从开放到封闭的过程。

而且,闭包(也是一个函数)对捕获变量作出的改变在闭包之外也是可见的,比如,上面的例子中,如果在addMore函数体中对more做了修改,在函数外部也可以看到这种变化。

另外,每次addMore函数被调用时都会创建一个新闭包。每个闭包都会访问闭包创建时活跃的more变量,比如:

图片:9.png



从上面可以看出,第1次调用addMore(10)的时候,捕获到的自由变量more的值是1,因此,addMore(10)的结果是11。第2次调用addMore(10)的时候,捕获到的自由变量more的值是9,因此,addMore(10)的结果是19。结论:每个闭包都会访问闭包创建时活跃的more变量。

高阶函数
就是让函数作为参数

图片:10.png



占位符语法
为了让函数字面量更加简洁,我们可以使用下划线作为一个或多个参数的占位符,只要每个参数在函数字面量内仅出现一次。

下面是一个实例(我们在Scala解释器中运行,从而可以立即看到运行结果):

图片:11.png



从上面运行结果可以看出,下面两个函数字面量是等价的。
x => x>0
_ > 0

4.正则表达式使用
val pattern = "[0-9]+".r
println(pattern findFirstIn "04a15c")  //找到第一个“一个或多个数字”的匹配
//输出 Some(04)
val pattern = "[0-9]+".r
println((pattern findAllIn "04a15c").mkString(",")) //找到所有匹配并用,合并为一个字符串
//输出 04,15
val pattern = "[0-9]+".r
println(pattern.replaceAllIn("04a15c","_")) //匹配到的所有替换为_
//输出 _a_c

5.异常处理

图片:12.png



本文源自草宝虫,转载目的在于传递更多信息,版权归原作者所有。


返回顶部