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

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