Scala基础
1、介绍
Scala是spark和kafka采用的编程语言,本质上是对java语言进行脚本化处理,使得开发效率更高。Scala的代码编写起来非常简洁,但并不简单,主要是很多语法比较诡异,对于刚刚接触到scala的人员来讲,往往有些摸不到头脑。
2、scala使用
打开scala的shell命令行窗口,输入1 + 1,可以直接进行求值运算。scala shell采用REPL方式进行交互,即read->evalute->print->loop。进入如下环境,运行效果如下图所示:
cmd>scala.bat
scala> 1 + 1
2.1 查看帮助
$scala>:help
2.2 退出
$scala>:quit
2.3 常量和变量
scala的量分为常量和变量,var是变量,可以重新赋值,val是常量,不可以重新复制。
// 变量
val x =10
// 错误,不能重新赋值
x = 20
var x = 10
// 正确
x = 20
2.4 类型推断与自动补全
val x = 100
val x:Int = 100
// tab键自动提示
x.<tab>
2.5 定义函数
递归函数必须显式定义函数,因为无法进行类型推荐。
// 参数必须定义类型,返回值可以不写,自动推断出来
def add(a:Int,b:Int) = {
a + b
}
// 显式定义返回值类型
def add(a:Int,b:Int):Int = {
a + b
}
// 递归实现阶乘
def frac(n:Int):Int = {
if(n == 1) 1 else n * frac(n - 1)
}
2.6 to和until
to和until都可以定义Range集合,to是闭区间,until是半闭半开区间。
// 1 .. 10
1 to 10
1.to(10)
// 1 .. 9
1 until 10
1.until(10)
2.7 字符串
// 取交集,lo
"hello".intersect("world")
2.8 BigInt
var b = BigInt(999999999)
b * b * b * b
2.9 ++/--
scala没有++或--操作,可以使用+=或-=,这些也都是方法。
var x = 1
// x ++
x += 1
x.+=(1)
// x --
x -=1
x.-=(1)
2.10 sqrt与pow
开方函数和幂函数都在math包下,因此需要导入才能使用:
import scala.math._
// 4开方=2.0
sqrt(4)
// 2的立方=8
pow(2,3)
2.11 表达式的值
scala的每个表达式或者代码块都有值,最后一行语句的值就是表达式的值。
val x = 2
// y = 1
val y = if (x < 1) -1 else 1
2.12 apply方法
scala为很多类提供了apply方法,可以方便进行各种对象的创建和元素的获取,apply方法名成通常可以省略,因此会让方法调用显得有些奇怪。
// 省略apply方法名
val arr = Array[Int](1,2,3)
val arr = Array[Int].apply(1,2,3) ;
// 省略了apply方法
"hello"(0)
"hello".apply(0)
2.13 粘贴模式
在scala shell可以使用粘贴模式来贴入大量代码:
# 进入粘贴模式的命令
$scala>:paste
# ctrl + d退出粘贴模式
2.14 读取控制台输入
// 字符串为控制台提示符
val name = readLine("请输入用户名:") ;
println(name) ;
运行结果如图:
2.15 循环
2.15.1 while
while循环同java相似,都是用boolean类型表示进行控制。
-
输出1~10
var n = 1 while(n < 11){ println(n) n += 1 }
-
输出99表格
var row = 1 while( row <= 9 ){ var col = 1 while( col <= 9){ printf("%dx%d=%d " ,col,row , (col * row)) } println() }
2.15.2 for
-
输出1~10
for(i <- 1 to 10){ println(i) }
-
输出99表格
for(r <- 1 to 10){ for(c <- 1 to r){ printf("%dx%d=%d " ,c,r , (c * r)) } println() }
运行结果如下:
-
带守卫条件的循环
for(i <- 1 to 3 ; j <- 4 to 6 if j != 5){ printf("%d : %d " , i , j ) }
如果j不等5的条件下,和i进行组合计算:
2.16 break
scala没有break语句,需要导入特定的函数来执行:
// 导入break函数
import scala.util.control.Breaks.break
for(i <- 1 to 10){
if(i % 3 == 0){
break
}
}
2.17 yield产生新集合
// 每个元素 * 2,组成新集合
for(i <- 1 to 5) yield i * 2
执行结果如下:
2.18 函数
-
定义函数
// 递归函数必须显式定义返回值类型 def fac(n:Int) : Int = { var result = 0 for(i <- (1 to n)){ result *= i } //最后一条语句是返回值 result }
-
参数默认值和带名参数
// 定义修饰串函数 def decorate(prefix:String="{{{" , str:String , suffix:String="}}}") = { prefix + str + suffix } //调用函数 decorate("<<<" , "hello" , ">>>") // 输出结果 "<<<hello>>>" // 使用带名参数向特定参数传值 decorate(str="world" , suffix="}}}")
-
变长参数
变长参数等价于java中的可变参数,即参数的类型个数可以不固定。
// 定义可变参数 def add(x:Int*) = { var sum = 0 for(i <- x){ sum += i } sum } // 传递多个参数 add(1,2,3) // 使用_*转换成数字序列 add(1 to 10 :_*)
-
过程
scala中将不带“=”的函数称之为过程,本质上和函数没有区别。
// 没有=号 def sayHi() { println("hello world!") }
2.19 lazy
lazy是延迟计算,即表达式不会立即求值,而是使用lazy字样作为占位符,等真正用到的时候再进行计算。spark的广播变量中使用该中方式进行的实现。
// lazy变量,不会出错
lazy var x = 1 / 0
// 出错
x
2.20 定义数组
-
一维数组
# 定义一个一维数组,长度为5个元素。 val arr = new Array[Int](5) # 定义一个一维数组,内部调用apply方法 var arr = Array[Int](5) var arr = Array[Int](1,2,3,4,5)
-
二维数组
// 定义二维数组 var arrr = new Array[Array[Int]](3) // 赋值 arrr[0] = Array[Int](1,2,3) # 三行四列数组 val arr = Array.ofDim[Int](3,4) # 第一行第二列为2 arr(0)(1) = 2
2.21 ArrayBuffer
数组缓冲区是可变数组,位于scala.collection.mutable包下,使用时需要进行导入。scala使用符号定义的方法有一定规律性:
-
当个符号的方法通常意味着操纵一个元素,如:
val arr = ArrayBuffer[Int](1,2,3) arr.+(4)
-
++
两个以上符号命名的方法意味着操纵的是集合元素,如:
arr.++(5 to 8)
-
+=
带有“=”号的方法意味着对自身的修改,如:
// 改变自身的内容 arr.+=(4)
-
常用方法
buf.trimEnd(3) // 删除最后的三个元素 buf.insert(0,1,2,3) // 在0位置插入1,2,3序列 buf.toArray() // 转换成数组 buf.reverse() // 倒序 buf.sum() // 求和 buf.max() // 最大值 buf.mkString(",") // 对元素拼接成串 buf.mkString("{",",","}") // 对元素拼接成串
2.22 java与scala集合互操作
java集合可以和scala进行相互无缝调用,需要导入隐式转换包才可以。代码如下:
/* 自动将scala buffer转换成java list */
val list:java.util.List[String] = new java.util.ArrayList[String]()
list.add("hello")
list.add("world")
def mybuf(buf:scala.collection.mutable.Buffer[String]) = println(buf.size())
import scala.collection.JavaConversions.asScalaBuffer
mybuf(list)
/* 自动将scala buffer转换成java list */
val buf = ArrayBuffer[String]("how" , "are" , "you")
def mylist(list:java.util.List[String]) = println(list.size())
import scala.collection.JavaConversions.bufferAsJavaList
mylist(buf)
3、map操作
val t = (1 , "tomas" , 12) // 元组
val t = (1 , "tomas") // 对偶,对偶是特殊的元组,只有两个元素。
val t = 1 -> "tomas" // 对偶
val map = Map(1->"tom" , 2->"tomas" , 3->"tomasLee") // 构造map
val map = Map((1,"tom"),(2,"tomas"),(3,"tomasLee")) // 构造map
map(1) // 指定key,访问value
map(2) //
// 迭代key-value
for((k,v) <- map){
println(k + " : " + v)
}
// 迭代key
for(k <- map.keys){
...
}
// 迭代values
for(v <- map.values){
...
}