scala是马丁.奥德斯克设计的,专门为程序员设计,广泛应用于大数据的语言。它同时支持面向对象和面向函数编程,运行scala需基于JVM,使用它需要提前安装好JDK和scala SDK。scala的的代码一行可以顶多行java代码,开发效率高,并且兼容java类库,scala编译完也是.class文件。另外大数据框架kafka和spark是基于scala开发的,因此想做流处理需要学习scala。
基本数据类型
scala中没有基本类型的说法,绝大多数类型(类似java类型)都封装成了类,以下是它的简图。
(1)Any是scala顶级父类。
(2)AnyVal是所有数值类型的父类,注意有一个Unit,它只有一个实例()。
(3)AnyRef是所有对象类型的父类,注意Null是它的子类,它的实例对象是null,可以赋值给任意对象类型。
(3)Nothing可以是任何类型的子类,可以表示不正常的返回值类型,如异常。
# RPEL交互方式 scala> def test():Nothing={ | throw new IllegalArgumentException() | } test: ()Nothing
变量和常量
变量声明的语法:'var 变量名:数据类型=数据值' 或者 'var 变量名=数据值',后者会进行自动类型转换。常量声明类似,使用val代表常量。
使用变量或常量需要标识符的支撑,scala中也有一套标识符规则。
标识符规则
(1)使用数字、字母、下划线和$符号;
scala> var name:String="clyang" name: String = clyang scala> var age:Int=28 age: Int = 28
(2)不能以数字开头;
(3)如果有特殊字符,标识符全部都需要是特殊字符;
scala> var +-*/ :Double=3.14 +-*/: Double = 3.14
(4)可以使用``来标记任何字符;
# 可以用scala的关键字,任何字符均可 scala> var `private`:String="test" private: String = test
(5)见名知意;
# year代表年,365天 scala> val year:Int=365 year: Int = 365 # 如果是常量,声明后不可以修改 scala> year=3650 <console>:13: error: reassignment to val year=3650 ^
类型转换
(1)自动类型推导
# 自动识别类型 scala> var name="clyang" name: String = clyang scala> var age=28 age: Int = 28
(2)手动指定向上类型,否则按自动类型推导出数据类型
# 默认是Double类型,手动指定Any类型 scala> var a:Any=3.14 a: Any = 3.14
(3)强制转换,从大往小转
# 强制Double转Int scala> var d:Double=3.14 d: Double = 3.14 scala> var i:Int=d.toInt i: Int = 3
(4)自定义类型转换,需自定义函数,可以显示调用和隐式调用。
显示调用
# 自定义类型转换函数 scala> def string2Int(str:String):Int={ | return Integer.parseInt(str) | } string2Int: (str: String)Int # 给一个字符串 scala> var str="268" str: String = 268 # 调用转换 scala> var number=string2Int(str) number: Int = 268
隐式调用
# 需使用implicit关键字 scala> implicit def string2Int(str:String):Int={ | return Integer.parseInt(str) | } warning: there was one feature warning; re-run with -feature for details string2Int: (str: String)Int scala> str res1: String = 268 scala> var number:Int=str number: Int = 268
(5)向上造型创建的对象,可以使用asInstanceOf来向下转。
# 定义Person类 scala> class Person{} defined class Person # 创建Any类型的对象,向上造型 scala> var p:Any=new Person() p: Any = Person@6a370f4 # 向下转 scala> var s:Person=p.asInstanceOf[Person] s: Person = Person@6a370f4
运算符
scala中运算符包括算术、赋值、关系、逻辑和位运算,注意没有三元运算,并且所有的运算符都封装成了方法。
参考菜鸟教程:https://www.runoob.com/scala/scala-operators.html
算术
注意一下,scala中的运算符是封装成了方法,因此a+b,其实就是a.+(b)的简写,其他依次类推。
scala> var a=500 a: Int = 500 scala> var b=20 b: Int = 20 # 加 scala> a+b res2: Int = 520 # 完整写法 scala> a.+(b) res3: Int = 520 # 以下三种方式等效,都可以加1 scala> a=a+1 a: Int = 501 scala> a+=1 scala> a res5: Int = 502 scala> a.+=(1) scala> a res7: Int = 503
如果有点,则计算点。
//运算符运用,有点先算点 println(3+5*7)//38 println(3+(5)*7)//38 println(7*3.+(5)) //56 println(7*3+5) //26 println(7*(3).+(5)) //56 println(3.+(5).*(7))//56
赋值
scala> var a=520 a: Int = 520 scala> var b=1314 b: Int = 1314 # 赋值运算的返回值类型为Unit,对应实例对象为() scala> var z:Unit=a=b z: Unit = () # a被赋值为1314 scala> a res8: Int = 1314
关系
就是类似java中的大于小于等于之类的。
scala> var r=1314>520 r: Boolean = true scala> var r="婚姻"=="车子房子票子" r: Boolean = false
逻辑
逻辑与、逻辑或和逻辑非。
scala> var r=true&&true r: Boolean = true scala> var r=true&&false r: Boolean = false
位运算
类似java中的位运算符,按位与、按位或、按位异或、取反、左移、右移、无符号右移。
//判断一个数是否是2的幂 println(8&7)//0 //左移比直接相乘快 println(4<<2)//16 println(~4)//-5 取反减1
流程控制
scala中没有switch-case,有条件判断和循环。
if条件判断
类似java,scala中if-else是有返回值结果的,根据if-else的{}最后一行来确认。
package day01.clyang.control import scala.io.StdIn /** * 流程控制 */ object IfDemo2 { def main(args: Array[String]): Unit = { //if-else是有返回值结果的,根据if-else的{}最后一行来确认 var i=StdIn.readInt() var result:String=if(i%2!=0){ println("~~~") "我是谁我在哪里" "奇数"//最后一行 }else{ "偶数"//最后一行 } //打印result println(result) } }
控制台输入奇数后,只返回最后一行'奇数'。
99 ~~~ 奇数
scala中也支持if-else if。
package day01.clyang.control import scala.io.StdIn /** * 多级if-else */ object IfDemo3 { def main(args: Array[String]): Unit = { var score=StdIn.readInt() var result:String=if(score>90) "优秀" else if(score>80) "良好" else if(score>=70) "一般" else "及格" //打印结果 println(result) } }
控制台输入测试,ok。
98 优秀
循环
可以使用while循环,和for循环。
(1)while循环
# while循环,返回值类型为Unit scala> var count=0 count: Int = 0 scala> var result=while(count<3){ | println("while") | count=count+1 | } while while while result: Unit = ()
(2)do-while循环,这个用的少
# do-while返回值类型也是Unit scala> var count=0 count: Int = 0 # scala中,也类似python中,字符串可以和数字相乘 scala> var result=do{ | println("*"*5) | count=count+1 | }while(count<3) ***** ***** ***** result: Unit = ()
(3)for循环
注意to和until的使用,两者均是函数。
# 准备一个数组 scala> var arr:Array[Int]=Array[Int](1,2,3,4,5) arr: Array[Int] = Array(1, 2, 3, 4, 5) # to为后包括 scala> var result=for(i <- 0 to arr.length-1){ | println(arr(i)) | } 1 2 3 4 5 result: Unit = () # until为后不包括 scala> var result=for(i <- 0 until arr.length){ | println(arr(i)) | } 1 2 3 4 5 result: Unit = ()
to和until都是函数,如果要指定步长,就不能省略.和( )。
# 指定步长,打印0到10范围的偶数 scala> for(i <- 0.to(10,2)){ | println(i) | } 0 2 4 6 8 10 # 倒着来 scala> for(i <- 10.to(0,-2)){ | println(i) | } 10 8 6 4 2 0 # reverse倒着来 scala> for(i <- 0 to 3 reverse){ | println(i) | } warning: there was one feature warning; re-run with -feature for details 3 2 1 0
for循环最后一行的结果,可以通过yield关键字把它放到一个集合,集合类型是Vector。
scala> import scala.io.StdIn import scala.io.StdIn # 输入5 scala> var n=StdIn.readInt() n: Int = 5 # 返回集合类型为Vector scala> var result=for(i <- 0 to n) yield i*i result: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 4, 9, 16, 25)
for循环中,如果嵌套了if判断,就构成了守卫循环。
# 打印100以内5的倍数,但是不是7的倍数 scala> for(i <- 0.to(100,5)){ | if(i%7!=0){ | println(i) | } | } 5 10 15 20 25 30 40 45 50 55 60 65 75 80 85 90 95 100 # 可以使用守卫循环 scala> for(i <- 0.to(100,5) if(i%7!=0)){ | println(i) | } 5 10 15 20 25 30 40 45 50 55 60 65 75 80 85 90 95 100
for循环嵌套,scala中还有大括号写法。
# 普通写法 scala> for(i <- 1 to 9){ | for(j <- 1 to i){ | print(i+"*"+j+"="+i*j+"\t") | } | println() | } 1*1=1 2*1=2 2*2=4 3*1=3 3*2=6 3*3=9 4*1=4 4*2=8 4*3=12 4*4=16 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81 # 两个循环嵌套到一起,scala中不推荐使用分号 scala> for(i <- 1 to 9; j <- 1 to i){ | print(i+"*"+j+"="+i*j+"\t") | if(i==j) println() | } 1*1=1 2*1=2 2*2=4 3*1=3 3*2=6 3*3=9 4*1=4 4*2=8 4*3=12 4*4=16 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81 # 大括号写法 scala> for{ | i <- 1 to 9 | j <- 1 to i | } | { | print(i+"*"+j+"="+i*j+"\t") | if(i==j){ | println() | } | } 1*1=1 2*1=2 2*2=4 3*1=3 3*2=6 3*3=9 4*1=4 4*2=8 4*3=12 4*4=16 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
Break
scala中,没有break和continue关键字,如果要退出循环,可以使用Break类来跳出循环。
(1)跳出循环,报异常,并且for循环后面语句不执行。
for(i <- 0.to(50,5)){ if(i==35) Breaks.break() println("我今年"+i+"岁,我依然很帅") } //测试是否执行后面语句 println("finished~~") # console显示没有打印 我今年0岁,我依然很帅 我今年5岁,我依然很帅 我今年10岁,我依然很帅 我今年15岁,我依然很帅 我今年20岁,我依然很帅 我今年25岁,我依然很帅 我今年30岁,我依然很帅 Exception in thread "main" scala.util.control.BreakControl
如果按以下这么写,即使跳出循环,依然执行for循环后面的语句。
Breaks.breakable( for(i <- 0.to(50,5)){ if(i==35) Breaks.break() println("我今年"+i+"岁,我依然很帅") } ) //测试是否执行后面语句 println("finished~~") # console显示打印了后面的语句 我今年0岁,我依然很帅 我今年5岁,我依然很帅 我今年10岁,我依然很帅 我今年15岁,我依然很帅 我今年20岁,我依然很帅 我今年25岁,我依然很帅 我今年30岁,我依然很帅 finished~~ # import scala.util.control.Breaks._后,这么写也行 breakable( for(i <- 0.to(50,5)){ if(i==35) break() println("我今年"+i+"岁,我依然很帅") } ) println("finished~~")
函数
函数在scala中地位非常高,是"一等公民",它可以作为函数的参数,也可以作为函数的返回值,并且可以定义在任何地方,函数定义的基本语法如下。
/* * 函数的格式 * def 函数名(参数列表):返回值类型={ * 函数体 * return 返回值 * } */
入门使用
常规写法。
scala> def max(i:Int,j:Int):Int={ | return if(i>j) i else j | } max: (i: Int, j: Int)Int # 调用 scala> max(1,3) res0: Int = 3
如果没有return,默认将函数体最后一行的结果返回。
scala> def sum(i:Int,j:Int):Int={i+j} sum: (i: Int, j: Int)Int scala> sum(1,3) res1: Int = 4
如果函数体只有一句,大括号可以省略,如果可以根据最后一行推导出返回值类型,方法返回值类型也可以省略。
scala> def sum(i:Int,j:Int)=i+j sum: (i: Int, j: Int)Int scala> sum(1,3) res2: Int = 4
如果没有指定方法的返回值类型,方法体不能用return,根据函数体最后一行来推导。
scala> def sum(i:Int,j:Int)={return i+j} <console>:10: error: method sum has return statement; needs result type def sum(i:Int,j:Int)={return i+j} ^
方法如果没有返回值类型,可以使用Unit作为返回值类型。
scala> def printShape(row:Int,col:Int):Unit={ | for(i <- 1 to row) | println("*"*col) | } printShape: (row: Int, col: Int)Unit scala> printShape(3,3) *** *** ***
如果没有写返回值类型,也没写等号,则默认返回值类型为Unit。
scala> def printTest(){ | println("this is return Unit") | } printTest: ()Unit # 如果函数没有参数,可以省略括号 scala> printTest this is return Unit
函数进阶
scala可以直接调用java api。
scala> def getRandom()=(Math.random()*11).toInt getRandom: ()Int # 调用时加括号 scala> getRandom() res7: Int = 0 # 没有参数,调用时括号可以省略 scala> getRandom res8: Int = 10 # 方法没有参数,方法括号也可以省略 scala> def getRandom=(Math.random()*11).toInt getRandom: Int scala> getRandom res9: Int = 3
scala中函数可以重载,类似java,根据方法签名来绑定执行的方法。
//scala中函数可以重载 def square(x:Int,y:Int)=x*y def square(r:Int)=3.14*r*r //根据参数不同,重载,好像一次只能调用一个,同时调用两个也只显示一个的结果
函数定义时如果没有(),调用时就不能加()。
scala> def test="this is test" test: String # 正常调用 scala> test res15: String = this is test # 加括号调用就报错 scala> test() <console>:12: error: not enough arguments for method apply: (index: Int)Char in class StringOps. Unspecified value parameter index. test() ^
高阶函数
将函数作为参数,或者函数的返回值也是函数,这样的函数叫做高阶函数,前面的闭包和柯理化就是高阶函数,返回值类型是函数。
(1)闭包
函数中嵌套函数,可以延长变量的生命周期,这是函数的闭包。
# 定义函数,打印最小值,如果有必要可以获取两个较大值的和 # 返回值为函数 scala> def min(x:Int,y:Int,z:Int)={ | var min=x | if(y<min) min=y | if(z<min) min=z | println("最小值为:"+min) | def sum(){ # 内部定义函数,返回值类型为Unit | println(x+y+z-min) | } | sum _ # 将sum一整个函数作为返回值,调用它才执行sum方法,不调用就不执行 | } min: (x: Int, y: Int, z: Int)() => Unit # 打印最小值,返回值类型是一个函数,() => Unit就是min方法返回值类型 scala> min(1,2,3) 最小值为:1 res17: () => Unit = <function0> # 调用sum方法 scala> min(1,2,3)() 最小值为:1 5
min函数执行完后,会移除出栈内存,如果将参数也移除,那接下来如果想调用sum方法就没有了参数,在scala中,只会将min函数移除出栈内存,而参数x,y,z会保留,供sum函数使用,这样延长了x,y,z变量的生命周期,这样使用函数嵌套延长变量生命周期的方式叫做函数的闭包。
闭包的应用练习如下,求两个数的积,如果有必要添加第三个数来求积。
scala> def product(x:Int,y:Int):Int => Int={ | println("两个数的积为:"+x*y) | def add(z:Int):Int={ | println("三个数的积为:"+x*y*z) | x*y*z | } | add _ | } product: (x: Int, y: Int)Int => Int scala> product(3,4) 两个数的积为:12 res19: Int => Int = <function1> scala> product(3,4)(5) 两个数的积为:12 三个数的积为:60 res20: Int = 60
(2)柯理化
柯理化是闭包的一种简化形式,写法更加简洁,但是使用没有闭包灵活,必须传入指定数目参数才能执行。
# 比较两个值的较大值 # 1 闭包写法 scala> def max(x:Int)={ | def max1(y:Int)={ | if (x>y) x else y | } | max1 _ | } max: (x: Int)Int => Int scala> max(1) res21: Int => Int = <function1> scala> max(1)(2) res22: Int = 2 # 2 柯理化写法 scala> def max2(x:Int)(y:Int)={ | if (x>y) x else y | } max2: (x: Int)(y: Int)Int scala> max2(1)(2) res23: Int = 2
(3)函数作为参数
函数可以作为参数,这也是高阶函数的一种。
# 函数作为参数传入 scala> def printResult(x:Int,y:Int,f:(Int,Int)=>Int):Unit={ | println(f(x,y)) | } printResult: (x: Int, y: Int, f: (Int, Int) => Int)Unit # 定义函数1 scala> def sum(x:Int,y:Int)=x+y sum: (x: Int, y: Int)Int # 定义函数2 scala> def minus(x:Int,y:Int)=x-y minus: (x: Int, y: Int)Int # 函数作为参数传入,根据函数不同,得到的结果也不同 scala> printResult(3,4,sum) 7 scala> printResult(3,4,minus) -1
函数作为参数传入,可以直接将匿名函数传入刚才定义的函数。
scala> printResult(3,4,(x:Int,y:Int)=>x*y) 12
如果参数类型确定,可以省略类型。
scala> printResult(3,4,(x,y)=>x*y) 12
如果参数只在匿名函数方法体中出现一次,可以用下划线来代替。
scala> printResult(3,4,_*_) 12
函数的递归
类似java和python,scala中也可以使用递归,需要注意的是递归需要指定返回值类型,因为无法通过类型自动推导。
# 求阶乘 scala> def getfactorial(num:Int):Int={ | if (num==1) return 1 //不写return,会报StackOverflowError,因为执行到此处,会依然往后执行,函数使用最后一行结果作为返回 | return num*getfactorial(num-1) | } getfactorial: (num: Int)Int scala> getfactorial(5) res33: Int = 120
可变参数
类似java中参数可以传入可变参数(使用...),scala中也可以实现,使用 " 变量类型* " 来表示任意多个可变参数。
# 求和,参数变长 scala> def sum(arr:Int*)={ | var sum=0 | for(i <- arr) sum+=i # 增强型for循环 | sum | } sum: (arr: Int*)Int scala> sum(1,2,3,4,5,6,7,8,9,10) res35: Int = 55
函数中可设定默认值
函数中可以给参数默认值,如果方法没有传入此参数就按默认值来计算。
scala> def getOffPrice(money:Double,offFactor:Double=1)=money*offFactor getOffPrice: (money: Double, offFactor: Double)Double # 按默认值计算 scala> getOffPrice(100) res36: Double = 100.0 # 按给定值计算 scala> getOffPrice(100,0.8) res37: Double = 80.0
懒值
scala中设置懒值,可以让懒值加载时才执行。
package boe.com.clyang.function /** * 懒值 * 加载时才真的运行 */ object LazyValue { def sum(i:Int,j:Int)={ println("sum is running~~~") i+j } def main(args: Array[String]): Unit = { var i=3 var j=4 //将sum求和设置为懒值 lazy val result=sum(i,j) # 线程等待3秒,自动回来,模拟这里有很多的代码 println("sleeping") Thread.sleep(3000) //只有这里真正加载时才执行sum求和 println(result) } }
控制台结果,可以看出虽然sum方法在写在前面,但是因为设置了懒加载,在等待3秒后,println打印时才真正加载执行。
sleeping sum is running~~~ 7
以上,是scala入门基础知识,记录一下备用。
参考资料:
(1)菜鸟教程
(2)scala官网
(3)https://blog.csdn.net/qq_31573519/article/details/82749188 守护循环
来源:https://www.cnblogs.com/youngchaolin/p/12306877.html