标签:col 开发效率 ceo shape control boolean assign java类库 没有
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,有条件判断和循环。
类似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
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()
^
将函数作为参数,或者函数的返回值也是函数,这样的函数叫做高阶函数,前面的闭包和柯理化就是高阶函数,返回值类型是函数。
函数中嵌套函数,可以延长变量的生命周期,这是函数的闭包。
# 定义函数,打印最小值,如果有必要可以获取两个较大值的和
# 返回值为函数
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
柯理化是闭包的一种简化形式,写法更加简洁,但是使用没有闭包灵活,必须传入指定数目参数才能执行。
# 比较两个值的较大值
# 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
函数可以作为参数,这也是高阶函数的一种。
# 函数作为参数传入
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 守护循环
标签:col 开发效率 ceo shape control boolean assign java类库 没有
原文地址:https://www.cnblogs.com/youngchaolin/p/12306877.html