Scala学习笔记
- Note
(1)函数可作为一个参数传入到方法中,而方法不行。
2、在Scala中无法直接操作方法,如果要操作方法,必须先将其转换成函数。有两种方法可以将方法转换成函数:
val f1 = m _
在方法名称m后面紧跟一个空格和下划线告诉编译器将方法m转换成函数,而不是要调用这个方法。也可以显示地告诉编译器需要将方法转换成函数:
object TestMap {
def ttt(f:Int => Int):Unit = {
val r = f(10)
println(r)}
val f0 = (x : Int) => x * x
//定义了一个方法
def m0(x:Int) : Int = {
//传递进来的参数乘以10
x * 10 }
//将方法转换成函数,利用了神奇的下滑线
val f1 = m0 _
def main(args: Array[String]): Unit = {
ttt(f0)
//通过m0 _将方法转化成函数
ttt(m0 _);
//如果直接传递的是方法名称,scala相当于是把方法转成了函数
ttt(m0)
//通过x => m0(x)的方式将方法转化成函数,这个函数是一个匿名函数,等价:(x:Int) => m0(x)
ttt(x => m0(x)) }}
输出结果为:
100
100
100
100
3、函数必须要有参数列表,而方法可以没有参数列表
4、在函数出现的地方我们可以提供一个方法
Scala的解释器在解析函数参数(function arguments)时有两种方式:
传值调用(call-by-value):先计算参数表达式的值,再应用到函数内部;
传名调用(call-by-name):将未计算的参数表达式直接应用到函数内部
在进入函数内部前,传值调用方式就已经将参数表达式的值计算完毕,而传名调用是在函数内部进行参数表达式的值计算的。
这就造成了一种现象,每次使用传名调用时,解释器都会计算一次表达式的值。
object ImplictClassDemo {
def main(args: Array[String]) {
delayed(time());}
def time() = {
println("获取时间,单位为纳秒")
println("haha")
System.nanoTime
}
def delayed( t: => Long ) = {
println("在 delayed 方法内")
println("xixix")
println("参数: " + t)}}
程序运行结果:
在 delayed 方法内
xixix
获取时间,单位为纳秒
haha
参数: 3678564244605
object ImplictClassDemo {
def main(args: Array[String]) {
delayed(time());
}
def time() = {
println("获取时间,单位为纳秒")
println("haha")
System.nanoTime
}
def delayed( t: => Long ) = {
println("在 delayed 方法内")
println("xixix")
println("参数: " + t)
t
}}
在 delayed 方法内
xixix
获取时间,单位为纳秒
haha
参数: 3775229046975
获取时间,单位为纳秒
Haha
object ImplictClassDemo {
def main(args: Array[String]) {
delayed(time());
}
def time() = {
println("获取时间,单位为纳秒")
println("haha")
System.nanoTime
}
def delayed( t: => Long ) = {
println("参数: " + t)
println("在 delayed 方法内")
println("xixix")
println("参数: " + t)
}
}
获取时间,单位为纳秒
haha
参数: 3950452511877
在 delayed 方法内
xixix
获取时间,单位为纳秒
haha
参数: 3950452676651
Scala 指定函数参数名
一般情况下函数调用参数,就按照函数定义时的参数顺序一个个传递。但是我们也可以通过指定函数参数名,并且不需要按照顺序向函数传递参数。
Scala 函数 - 可变参数
Scala 允许你指明函数的最后一个参数可以是重复的,即我们不需要指定函数参数的个数,可以向函数传入可变长度参数列表。
Scala 通过在参数的类型之后放一个星号来设置可变参数(可重复的参数)。例如:
递归函数:
object Test {
def main(args: Array[String]) {
for (i <- 1 to 10)
println(i + " 的阶乘为: = " + factorial(i) )
}
def factorial(n: BigInt): BigInt = {
if (n <= 1)
1
else
n * factorial(n - 1)
}
}
Scala 高阶函数
高阶函数(Higher-Order Function)就是操作其他函数的函数。Scala 中允许使用高阶函数, 高阶函数可以使用其他函数作为参数,或者使用函数作为输出结果。
object Test {
def main(args: Array[String]) {
println( apply( layout, 10) )
}
// 函数 f 和 值 v 作为参数,而函数 f 又调用了参数 v
def apply(f: Int => String, v: Int) = f(v)
def layout[A](x: A) = "[" + x.toString() + "]"
}
匿名函数
Scala 中定义匿名函数的语法很简单,箭头左边是参数列表,右边是函数体。
使用匿名函数后,我们的代码变得更简洁了。
下面的表达式就定义了一个接受一个Int类型输入参数的匿名函数:
var inc = (x:Int) => x+1
上述定义的匿名函数,其实是下面这种写法的简写:
def add2 = new Function1[Int,Int]{
def apply(x:Int):Int = x+1;
}
我们也可以不给匿名函数设置参数,如下所示:
var userDir = () => { System.getProperty("user.dir") }
Option的类型是函数:
- scala特点
面向对象编程
函数式编程
静态类型语言
(动态类型语言如Python(变量a的数据类型在运行阶段确定)和静态类型语言如java scala(变量a的数据类型在编译阶段确定))
基于JVM(aa.scalaàaa.class-àJVM)
学习scala原因:
- 速度快
- 优雅简洁
- 融入大数据生态圈,深入学习spark
- 变量
var 变量名=初始化值
var 变量名:数据类型=初始化值
注意:
- 定义变量的时候需要初始化
- 定义变量的时候可以不指定变量的数据类型,系统会根据变量的初始化值推断变量的数据类型。var a=1 或者var a:Int=1
- 常量
val 变量名=初始化值
val 变量名:数据类型=初始化值
注意:
val修饰的变量,相当于Java中final修饰的变量
val修饰的变量,变量的类型是值类型(相当于java中的基本数据类型,int ,double,boolean),值是不可以修改的。
val a=10
a=100(错误不可修改)
val修饰的变量,变量的类型是引用类型,引用不可变,引用的内容可变
val a1=Array(1,2,3)
val a2=Array(4,5,6)
a1=a2 //不可以,引用不可变
a1(0)=10//可以的,引用的内容可变
val修饰的变量还可以用lazy修饰,值是在需要使用的时候才会赋值
官方推荐使用val
- 数据类型和操作符
数据类型
- 值类型(java中的基本数据类型)和引用类型
- 值类型也是类类型,相当于java中的包装类,没有基本数据类型和包装类之分
操作符
数学运算符
关系运算符
逻辑运算符
位运算符
比较对象 == !=
- Scala中的运算符都是方法的重载,是方法的调用
- scala中没有++, --,可用+=,-=来代替
- 表达式
就是一个语句块,包含一条或者多条语句
特点:
- 表达式是有返回值的
- 返回值是表达式中最后一条语句的执行结果
条件表达式
含有if/else的表达式
块表达式
一条语句或者多条语句
- 循环
for:
for(i <- 表达式、数组、集合)
while
while(条件语句){表达式}
do while
do{表达式}while{条件语句}
- 方法
定义语法:
def 方法名(参数名1:参数类型,参数名2:参数类型,…):返回类型=方法体
返回类型可省略,如果是递归方法则不可省略。系统会根据表达式的返回值推断方法的返回值的类型。
上述报错的原因是,方法的返回值定义的是int类型,而方法体表达式最后一行是print函数,它的返回值是Unit类型(注意表达式的返回值是它最后一行语句的返回值)。因此要将方 法返回值改为Unit或缺省,由系统自己去判断。
无参方法
带有默认值参数的方法
可变长参数方法
- 函数
定义函数时格式:val 变量名 = (输入参数类型和个数) => 函数实现和返回值类型和个数
“=”表示将函数赋给一个变量
“=>”左面表示输入参数名称、类型和个数,右边表示函数的实现和返回值类型和参数个数
定义函数
无参函数
匿名函数定义, 左边是参数 右边是函数实现体 (x: Int)=>{}
函数类型的声明,左边是参数类型,右边是方法返回值类型 (Int)=>(Int)
函数作为参数的表现形式——函数名:传入参数*=>返回值
def getName(func:String=>Unit,name:String){ //getName两个参数,第一个是函数参//数,第二个是name
func(name)
}
f(p :=>Int)
注意:def a(f: =>Int)={}冒号后面要有个空格
在Scala中,你不需要给每一个函数命名,没有将函数赋给变量的函数叫做匿名函数
由于Scala可以自动推断出参数的类型,所有可以写的跟精简一些
还记得神奇的下划线吗?这才是终极方式
//第一种:最直观的方式 (Int) => Int
//new_list = list.map((x: Int) => x * 3)
//第二种:由于map方法知道你会传入一个类型为(Int) => Int的函数,你可以简写
//new_list = list.map((x) => x * 3)
//第三种:对于只有一个参数的函数,你可以省去参数外围的()
//new_list = list.map(x => x * 3)
//第四种:(终极方式)如果参数在=>右侧只出现一次,可以使用_
new_list = list.map(_ * 3)
- 集合
集合是存储各种数据类型对象的一个容器
- 是一个容器
- 一般放同种数据类型的对象
- 一般存放多个对象
集合分为不可变集合和可变集合。
不可变集合:不可修改,但是可以模拟修改或者删除等操作。返回一个新的集合,原来集合不变。
可变集合:可修改,更新,扩充。
三大类
Set 序列 map
- 定长数组
- 变长数组
数组变换
- List
- Map
- 元组
- Set
特点
set中的元素是不许重复的
set中元素是无序随机的
- 集合中重要函数
- sum max min
- filter
- flatten 是对集合中包含的集合的集合做处理
- map
- flatMap 有点类似于map+flatten
- forall foreach
- foldLeft foldRight reduceLeft reduceRight
reduceLeft:从左边往右边计算 reduceRight相反 reduce相当于redeceLeft
- java中面向对象的概念
类:类是一类事物的抽象
对象:类的一个实例
foldLeft foldRight 相对于reduceLeft 和reduceRight要多一个多传入一个参数
- 类和属性定义
this.age-obj.age会出错,因为private[this]修饰的自由当前对象可以访问。
- 构造函数
19.1默认的主构造函数是无参构造函数
(1)类自带无参构造函数函数
(2)主构造函数执行类中定义的所有语句
class ConstructorDemo{
var a:Int=0
println("constructor")
}
object ConstructorDemo{
def main(args: Array[String]): Unit = {
val obj=new ConstructorDemo()
println(obj.a)
}
}
19.2自定义辅助构造函数
class ConstructorDemo{
var a:Int=0
println("constructor")
def this(a1:Int){
this()//首先要调用主构造函数或者其他的辅助构造函数
this.a=a1
}
}
object ConstructorDemo{
def main(args: Array[String]): Unit = {
//val obj=new ConstructorDemo()
val obj=new ConstructorDemo(1000)
println(obj.a)
}
}
19.3自定义带参数的主构造函数
class ConstructorDemo(var b:Int){
println(b)
}
object ConstructorDemo{
def main(args: Array[String]): Unit = {
val obj=new ConstructorDemo(100)
println(obj.b)
}
}
注意当构造函数中的参数用var修饰时,会被当做是类中的属性,如果没有var修饰时,则不会
class ConstructorDemo(b:Int){
println(b)
}
object ConstructorDemo{
def main(args: Array[String]): Unit = {
val obj=new ConstructorDemo(100)
println(obj.b)
}
}
Error:(8, 17) value b is not a member of ConstructorDemo
println(obj.b)
19.4在自定义的带参数的主构造函数中定义辅助构造函数
class ConstructorDemo(b:Int){
println(b)
def this(a1:Int,b1:Int){
this(a1) //调用主构造函数
}
}
object ConstructorDemo{
def main(args: Array[String]): Unit = {
val obj=new ConstructorDemo(100)
}
}
19.5定义私有的主构造函数
class ConstructorDemo private(b:Int){
println(b)
def this(a1:Int,b1:Int){
this(a1)
}
}
object ConstructorDemo{
def main(args: Array[String]): Unit = {
val obj=new ConstructorDemo(100)
}
}
- 单例对象和伴生对象
单例对象,以object关键字修饰的就是单例对象
//单例对象,scala中没有静态方法和静态字段,这个作用类似
//相当于java中的一个工具类,可以定义工具函数和常量
//单例对象第一次调用时初始化
object Logger {
def log(msg:String): Unit ={
println(s"Info:$msg")
}
}
class Test{
def method={
Logger.log("hahah")
}
}
object LoggerTest{
def main(args: Array[String]): Unit = {
Logger.log("haha")
val obj=new Test
obj.method
}
}
类的伴生对象,伴生对象和类可以互相访问彼此的私有属性或者方法。类和对象定义在同一个源文件中且名字相同,则是伴生类和伴生对象。
class AccountInfo {
var id=AccountInfo.newUniqueNumber
}
object AccountInfo{
private var lastNumber:Int=10
private def newUniqueNumber={
lastNumber+=1
lastNumber
}
}
object test{
def main(args: Array[String]): Unit = {
val obj=new AccountInfo
println(obj.id)
}
}
程序的执行可以在单例对象中定义main方法,也可以在应用程序对象中定义要执行的语句
import javafx.application.Application
class AccountInfo {
var id=AccountInfo.newUniqueNumber
}
object AccountInfo{
private var lastNumber:Int=10
private def newUniqueNumber={
lastNumber+=1
lastNumber
}
}
/*
object test{
def main(args: Array[String]): Unit = {
val obj=new AccountInfo
println(obj.id)
}
}*/
object Test extends App{
val obj=new AccountInfo
println(obj.id)
}
此时省略main方法时要导入import javafx.application.Application
- apply方法和unapply方法
注意当出现这个问题
解决:打开run->edit configurations
将working directory重新选一下
class User(val name:String,val password:String) {
}
object User{
def apply(name:String,password:String)=new User(name,password)
}
object userTest{
def main(args: Array[String]): Unit = {
val obj=new User("zhangsan","12345")
println(obj.isInstanceOf[User])
val obj1=User("zhangsan","123456")//用apply方法可以创建一个类的
//对象
println("result="+obj1.isInstanceOf[User])
}
}
true
result=true
class User(val name:String,val password:String) {
}
object User{
def apply(name:String,password:String)=new User(name,password)
def unapply(user: User): Option[(String, String)] = { //unapply方法可以根据传入的对象将对象的属
//性提取出来
if(user==null) None
else
Some(user.name,user.password)
}
}
object userTest{
def main(args: Array[String]): Unit = {
val obj=new User("zhangsan","12345")
println(obj.isInstanceOf[User])
val obj1=User("zhangsan","123456")
println("result="+obj1.isInstanceOf[User])
obj match{
case User(name ,password)=>println(name+":"+password)
case _ =>println("None")
}
}
}
- 继承
通过extends关键字定义,继承父类的所有属性和方法。
重写父类的非抽象方法,要用override
重写父类的抽象方法,override可选。
final修饰的类,方法,属性不可以被重写
class Point(val xc:Int,val yc:Int) {
var x:Int=xc
var y:Int=yc
def move(dx:Int,dy:Int)={
x=x+dx
y=y+dx
println("x="+x+",y="+y)
}
}
class Location(override val xc:Int,override val yc:Int,val zc:Int) extends Point(xc,yc){
var z:Int=zc
def move(dx:Int,dy:Int,dz:Int)={
x=x+dx
y=y+dx
z=z+dz
println("x="+x+",y="+y+",z="+z)
}
}
object test{
def main(args: Array[String]): Unit = {
val obj=new Location(5,6,7)
obj.move(1,2,3)
}
}
注意:
1.判断对象是否属于给定的类
obj.isInstanceOf[Location]
2.类的类型转换
obj.asInstanceOf[Location]
3.获取类的信息
classOf[Location]
- 抽象类
抽象类不能被实例化,抽象类可以抽象字段。
抽象字段:没有初始值的字段
抽象方法:没有方法体的方法
abstract class Persons {
var name:String
def id:Int
}
抽象类可以有具体的方法,这个方法如果在子类中重写,一定要用override.如若是抽象方法,override可用可不用
- trait
优先推荐trait
//定义一个带有抽象方法的特质
trait Iterrator[A] {
def hasNext:Boolean
def next():A
}
//定义一个带有实现的方法trait
trait ConsoleLog{
def log(msg:String)={
println(msg)
}
}
//定义一个类实现trait
class IntIterator(to:Int) extends Iterrator[Int] with ConsoleLog {
private var current=0
override def hasNext: Boolean =currentoverride def next(): Int ={
if(hasNext){
log("has next")
val t=current
current+=1
t
}
else 0
}
}
object TraitTest {
def main(args: Array[String]): Unit = {
val iterator=new IntIterator(10)
println(iterator.next())
println(iterator.next())
println(iterator.next())
}
}
//trait可以为类提供可以堆叠的改变
trait Logger{
def log(msg:String)
}
//子trait实现父trait里抽象方法
trait ConsoleLogger extends Logger{
override def log(msg: String): Unit = println(msg)
}
//给日志加上时间戳
trait TimestampLogger extends ConsoleLogger{
override def log(msg: String): Unit = super.log(s"${java.time.Instant.now()}$msg")
}
//如果日志时间过长,对日志进行截断显示
trait ShortterLoger extends ConsoleLogger{
val maxLength=15
override def log(msg: String): Unit = super.log(
if(msg.length<=maxLength) msg
else s"${msg.substring(0,maxLength-3)}..."
)
}
class Account{
protected var balance:Double=0.0
}
class SavingAccount extends Account with ConsoleLogger {
def withdraw(amout: Double) = {
if (amout > balance) log("insufficent funds")
else balance -= amout
}
}
object TraintTest2 {
def main(args: Array[String]): Unit = {
/*var acc1=new SavingAccount with ConsoleLogger with TimestampLogger with ShortterLoger
var acc2=new SavingAccount with ConsoleLogger with ShortterLoger with TimestampLogger
acc1.withdraw(100.0)
acc2.withdraw(100.0)*/
}
}
- 样例类
object CaseClassDemo {
def main(args: Array[String]): Unit = {
//定义样例类
//默认带有apply方法
//构造函数的默认参数默认是public val修饰的,值不可以修改但是可以改为var,这样值就可以修改,但是不推荐
case class Message(send:String,recipient:String,body:String)
//创建样例类对象
val message1=Message("Jery","Tom","I Love you")
println(message1)
//样例类的比较,基于值或者结构的比较,而不是基于引用的比较
val message2=Message("Jery","Tom","I Love you")
if(message1==message2)
println("same")
else println("different")
//样例类的拷贝,浅拷贝
val message3=message1.copy()
println(message3)
//不完全拷贝,对部分参数赋值
val message4=message1.copy(send = "lingxiao")
println(message4)
}
}
- 模式匹配
Java switch
常量模式匹配
变量模式匹配
通配符模式匹配
样例类匹配
类型匹配
object PatternDemo {
def main(args: Array[String]): Unit = {
//常量模式匹配
//1.常量字面值匹配
val site="qianfeng.com"
site match{
case "qianfeng.com" => println("1.success")
case _=>println("1.fail") //相当于java中的default,不需要break语句
}
//2.常量变量匹配
val QIANFENG="qianfeng.net" //常量变量的匹配,变量名一定要大写
//val qianfeng="qianfeng.net"
site match{
// case qianfeng => println("2.success")
case QIANFENG => println("2.success")
case _=>println("2.fail") //相当于java中的default,不需要break语句
}
//3.变量模式匹配
val qianfeng="qianfeng.net"
site match{
case qianfeng => println(qianfeng+" 3.success") //变量模式匹配,site 会把值赋给qianfeng
case _=>println("3.fail") //相当于java中的default,不需要break语句
}
//4.通配符模式匹配,通配符用_表示,可以理解为占位符
val list =List(1,2,3)
list match{
case List(_,_,3)=>println("4.success") // 判断List是否符合第三个元素是3,前两位不管
case _ => println("4.fail")
}
}
}
//样例类匹配
abstract class Notification
//定义不同信息的样例类
case class Email(sender:String,title:String,body:String) extends Notification
case class SMS(caller:String,message:String) extends Notification
case class VoiceRecording(contactName:String,link:String) extends Notification
object PatternDemo2 {
//做信息的识别
def main(args: Array[String]): Unit = {
//样例类匹配,做信息的甄别
def showNotification(notification: Notification)={
notification match {
case Email(sender,title,body) if(sender=="lingxiao")=> "you get a Email Message from "+sender+" context: "+body
case SMS(caller,message) => "you get a SMS message from " + caller
case VoiceRecording(contactName,link) => "you get a voiceRecording message from "+contactName
case _ =>""
}
}
//创建一条信息
val email=Email("lingxiao","important","I love you")
println(showNotification(email))
}
}
//类型匹配
val arr=Array("string",1,2.0,'c')
//随机取数组的元素
val obj=arr(Random.nextInt(4))
println(obj)
obj match {
case x:Int => println(x)
case x:String => println(x.toUpperCase())
case x:Double => println(x)
case _ => println("failed")
}
Option类型的模式匹配
- 偏函数
1.使用标准的方法定义偏函数
object PartialFunctionDemo {
//创建一个普通函数
val div1=(x:Int)=> 100/x
//定义一个偏函数
val div2=new PartialFunction[Int,Int] {
override def isDefinedAt(x: Int): Boolean = x!=0
override def apply(x:Int): Int = 100 / x
}
def main(args: Array[String]): Unit = {
// div1(0) //会出错
println(div2.isDefinedAt(1))
if(div2.isDefinedAt(0))
div2.apply(0)
else println("不允许运算")
if(div2.isDefinedAt(1))
println(div2.apply(1))
else println("不允许运算")
println(div2.isDefinedAt(0))
}
2.简洁方式定义偏函数
偏函数本质上是由多个case语句组成的针对每一种可能的参数分别进行处理的一种“结构较为特殊”的函数,那特殊在什么地方呢?对,就是case语句,前面我们提到,case语句声明的变量就是偏函数的参数,既然case语句只能声明一个变量,那么偏函数受限于此,也只能有一个参数!说到底,类型PartialFunction无非是为由一组case语句描述的函数字面量提供一个类型描述而已,case语句只接受一个参数,则偏函数的类型声明自然就只有一个参数。
object PartialFunctionDemo {
val div3:PartialFunction[Int,Int]={
//第一个参数是要处理的类型,第二个参数是返回的类型
case d:Int if(d!=0) => 100/d
case _ => 0
}
def main(args: Array[String]): Unit = {
println(div3(0))
}}
object PartialFunctionDemo {
val div3:PartialFunction[Int,String]={
case d:Int if(d!=0) => (100/d).toString
case _ => "by zero"
}
def main(args: Array[String]): Unit = {
println(div3(1))
}
}
object PartialFunctionDemo {
val res:PartialFunction[Int,String]={
case 1 => "one"
case 2 => "two"
case _ =>"other"
}
def main(args: Array[String]): Unit = {
println(res.isDefinedAt(1))
println(res(10))
}
}
object PartialFunctionDemo {
val res:PartialFunction[Int,String]={
case 1 => "one"
case 2 => "two"
case _ =>"other"
}
//orElse 组合多个偏函数成为一个整体
val r1:PartialFunction[Int,String]={case 1=>"one"}
val r2:PartialFunction[Int,String]={case 2=>"two"}
val r3:PartialFunction[Int,String]={case _=>"other"}
val res2 = r1 orElse r2 orElse r3 //相当于res这个函数
//andThen,将多个偏函数串行执行
val r4:PartialFunction[Int,String]={case cs if(cs==1) =>"one"}
val r5:PartialFunction[String,String]={case cs if(cs.eq("one")) =>"1"}
val r6:PartialFunction[String,Double]={case cs if(cs.eq("1"))=>1}
val res3:(Int=>Double)= r4 andThen r5 andThen r6
//Int=>Double 最开始传入的是Int类型,最后返回的是Double类型
def main(args: Array[String]): Unit = {
/* println(res.isDefinedAt(1))
println(res(10))
println(res2(1))
*/
println(res3(1))
}
}
- 密封类
用关键字sealed修饰的类或者特质
约束:不能再类定义文件之外定义它的子类
作用:
- 可以避免滥用继承
- 用在模式匹配中,检查所有的匹配情况是否匹配完全。而不用使用通配符的情况。
sealed abstract class Furniture
case class Couch() extends Furniture
case class Chair() extends Furniture
object SealedDemo {
def findPlaceToSit(furniture: Furniture)=furniture match {
case a:Couch => "lie on the couch"
case a:Chair => "sit on the chari"
//case _=>""不需要这个,因为Furniture是sealed密封类
}
val chair =Chair()
def main(args: Array[String]): Unit = {
println(findPlaceToSit(chair))
}
}
- Option
如何定义Option类型
map.getOrElse(“c”,”默认值”),如果map中键c不存在,则返回默认值。也可以使用Option类型,它有两个类,一个用例类Some,一个None
object OptionDemo {
def main(args: Array[String]): Unit = {
val map=Map("a"->1,"b"->2)
println(map("b"))
//println(map("c"))
println( map.getOrElse("c","morenzhi"))
val a:Option[Int]=map.get("a")
println(a.getOrElse())
val b:Option[Int]=map.get("c")
println(b.getOrElse())
}
}
- 字符串插值器
object StringDemo {
def main(args: Array[String]): Unit = {
//插值器 f s raw
//s字符串插值器
val name = "lingxiao"
val res =s"Hello,$name"
// 对${ }中的表达式进行运算
val res1= s"1+1=${1+1}"
println(res)
println(res1)
//f插值器,对字符串进行格式化
val height=1.9d
val heigt1=1
val res2=f"$heigt1%2.5f is $height%2.2f meters tall" //%2.2f必须紧跟着$height
println(res2)
//raw插值器,类似于s插值器,不对其中的内容做转换
val str=s"a\nb"
println(str)
val str2=raw"a\nb"
println(str2)
}}
- 文件操作
//读取文件一行
/* //读取文件一行
val source = Source.fromFile("src/filetest.txt")
//获取文件行迭代器
val lines=source.getLines()
for(line<-lines)
println(line)
//关闭源文件
source.close();*/
/* //按每一个字符读取文件
val source1=Source.fromFile("src/filetest.txt")
val iter=source1.buffered
while(iter.hasNext){
println(iter.next())
}
source1.close()
*/
/* //读取网络文件
val source2=Source.fromURL("https://baike.baidu.com/item/Scala")
val lines=source2.getLines()
for(line<-lines)
println(line)
source2.close()*/
//写文件
val out = new PrintWriter("file1.txt")
for(i<-1 to 100)
out.println(i)
out.close()
- 正则表达式
主要用来对字符串进行检索匹配
import scala.util.matching.Regex
object RegDemo {
def main(args: Array[String]): Unit = {
//构造一个正则表达式
val pattern1="[0-9]+".r
val pattern2=new Regex("[0-9]+")
//如果正则表达式有\,"", 可以用""" """
val pattern3=""" \s+[0-9]+\s"""
val matchStr="99bottles,100bottles"
//findAllIn返回所有匹配项的迭代器
for(item<- pattern1.findAllIn(matchStr))
println(item)
//返回首个匹配项
println(pattern1.findFirstIn(matchStr))
//检查字符串的开始部分是不是能匹配
println(pattern1.findPrefixOf(matchStr))
//使用传入的字符串替换首个匹配项
println(pattern1.replaceFirstIn(matchStr,"xxx"))
//使用传入的字符串替换所有匹配项
println(pattern1.replaceAllIn(matchStr,"xxx"))
}
}
- 高阶函数
高阶函数:一个函数的参数是函数,或者它的返回值是函数。
object HFunDemo {
def main(args: Array[String]): Unit = {
//传入参数是函数
val arr=Array(1,2,3,4,5)
val fun=(x:Int)=>x*2
val res=arr.map(fun) //map是高阶函数
println(res.toBuffer)
//传入匿名函数
val res1=arr.map((x:Int)=>x*2) //val res1=arr.map(_*2)
//返回值是函数
def urlBuilder(ss1:Boolean,domainName:String):(String,String)=>String={
val schema =if(ss1) "https://" else "http://"
(endpoint:String,query:String)=>s"$schema$domainName/$endpoint?$query"
}
val domainName="www.baidu.com"
def getUrl:(String,String)=>String =urlBuilder(ss1=true,domainName)
//val getUrl:(String,String)=>String =urlBuilder(ss1=true,domainName) //定义一个变量getUrl,变量的类型是函数来接受 urlBuilder的返回值
val endpoint ="users"
val query="id=1"
val res3=getUrl(endpoint,query)
println(res3)}}
- 闭包
闭包是一个函数,函数的返回值依赖于函数外部的一个或者多个变量
var factor=10 //变量factor和multiply3函数形成了一个闭包
val multiply3=(x:Int)=>{
factor+=10
x*factor
}
- 柯里化
柯里化是把接收多个参数的函数变成接收一个单一参数的函数,返回一个接收余下参数的新函数
- 方法的嵌套和多态
object MethodDemo extends App {
//方法的嵌套:方法体里面定义其他嵌套
//阶乘
def fatorial(x:Int):Int={
def fact(x:Int,accumulator:Int):Int={
if(x<=1) accumulator
else fact(x-1,x*accumulator)
}
fact(x,1)
}
println(fatorial(5))
//方法的多态:方法可以通过类型实现参数化,类似泛型
def listOfDuplicates[A](x:A,length:Int):List[A]={
if(length<1) Nil
else
x::listOfDuplicates(x,length-1)
}
println(listOfDuplicates(3,5))
println(listOfDuplicates("ss",10))
}
- 隐式转换
//定义隐式类,可以把File类转成自定义的隐式类RichFile
//使用隐式类做已有类的动能的扩展
implicit class RichFile(from:File){
def read=Source.fromFile(from.getPath).mkString
}
val contents= new File("src/file1.txt").read
println(contents)
}
object ImplictClassDemo extends App {
//定义一个隐式类
//隐式类智能定义在类,trait,object内部
implicit class IntWithTimes(x:Int){
def times[A](f: =>A)={
def loop(current:Int):Unit={ //递归方法需要指明其返回类型
if(current>0){
f
loop(current-1)
}
}
loop(x)
}
}
//隐式类的构造函数只能带一个非隐式参数
//implicit class Indexer[T](collection:Seq[T],index:Int)
implicit class Indexer[T](collection:Seq[T])(implicit index:Int)
//在同一作用域,不能有方法或者对象,成员和隐式类同名
}
- 闭包