scala基础内容 函数,懒值,数组
函数(def)
/*
def 定义函数的关键字
name 形参
String 数据类型
: 执行语句
*/
def fun1(name:String):String="Hello:"+name;
函数参数的求值策略
call by value:当实参赋值给形参之后,就直接求值,只求一次值
call by name:当实参赋值给形参之后,并不直接求值,而是在调用的时候才会求值
代码举例:
scala> def test1(x:Int,y:Int) : Int = x+x
test1: (x: Int, y: Int)Int
scala> test1(3+4,8)
res0: Int = 14
scala> def test2(x: => Int,y: => Int) : Int = x+x
test2: (x: => Int, y: => Int)Int
scala> test2(3+4,8)
res1: Int = 14
执行过程讲解:
test1和test2显示的值是一样的,都是14,但是执行的策略确实不相同的
test1是当3+4赋值给x的时候,就直接计算出结果为7,当调用test1的时候,进行的是x+x的操作,得出结果为14
test2则是当3+4赋值给x的时候,x等于3+4,并没有进行计算,只有到调用test2的时候,才会将x+x操作中的x替换为3+4,即x+x转换为(3+4)+(3+4),然后得到结果为14
举例:
x 是 call by value , y 是 call by name
def bar(x:Int,y: => Int) : Int = 1
定义一个死循环函数
def loop() : Int = loop
调用 bar 函数:
1、bar(1,loop)
2、bar(loop,1)
哪种方式会产生死循环?
第二种方式
解析:
1、y 每次在函数中用到时,才会被求值,bar函数没有用到y,所以不会调用loop。
2、x call by value ,对函数参数求值,并且只求一次,所以会产生死循环。
Scala中函数参数的类型
默认参数
当调用函数的时候,没有进行赋值,则使用默认值
//设置默认参数为aaa
scala> def fun1(name:String="aaa"):String="Hello:"+name;
fun1: (name: String)String
//当没有传实参的时候,使用默认值
scala> fun1()
res5: String = Hello:aaa
//当传递实参的时候,使用传递的实参
scala> fun1("sdfsdf")
res6: String = Hello:sdfsdf
代名参数
当有多个默认参数的时候,通过代名参数可以确定是给那个参数赋值
scala> def fun1(no:Int=1,name:String="aaa"):String=no + " : "+name;
fun1: (no: Int, name: String)String
scala> fun1()
res7: String = 1 : aaa
scala> fun1(no=3)
res8: String = 3 : aaa
scala> fun1(name="hahaha")
res9: String = 1 : hahaha
scala> fun1("hahaha")
<console>:13: error: type mismatch;
found : String("hahaha")
required: Int
fun1("hahaha")
可变参数
类似于java中的可变参数,即参数数量不固定
scala> def sum(args:Int*) = {
| var result = 0
| for(s <- args) result += s
| result}
sum: (args: Int*)Int
scala> sum(1,2,3)
res0: Int = 6
懒值(lazy)
定义:如果变量是lazy的,他的初始化会被延迟,推迟到第一次使用该常量的时候
个人感觉跟函数中的call by name类似
scala> val a : Int = 10
a: Int = 10
//y不是lazy,在定义后直接进行计算
scala> val b : Int = a+10
b: Int = 20
//z是lazy,所以在定以后没有直接进行计算
scala> lazy val z : Int = b + a
z: Int = <lazy>
//而是在调用的会后才进行计算
scala> z
res3: Int = 30
铺垫:
Spark的核心是RDD(数据集合),Spark提供很多方法,操作RDD,算子。
算子分为两种:
1、Transformation : 延时加载,不会触发计算
2、Action : 会触发计算
对比:使用lazy读取一个不存在的文件
//不使用lazy读取一个不存在的文件,会产生异常
scala> val words = scala.io.Source.fromFile("H:\\tmp_files\\studen1231312312t.txt").mkString
java.io.FileNotFoundException: H:\tmp_files\studen1231312312t.txt (系统找不到指定的文件。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at scala.io.Source$.fromFile(Source.scala:91)
at scala.io.Source$.fromFile(Source.scala:76)
at scala.io.Source$.fromFile(Source.scala:54)
... 32 elided
//使用lazy读取一个不存在的文件,不会产生异常,只有在调用words的时候才会出现异常
scala> lazy val words = scala.io.Source.fromFile("H:\\tmp_files\\studen1231312312312t.txt").mkString
words: String = <lazy>
数组(Array)
数组创建之后的默认值
整形(Int)默认值是0
字符串(String)默认值是null
浮点数(Double)默认值是0.0
scala> val a = new Array[Int](10)
a: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
scala> val b = new Array[String](15)
b: Array[String] = Array(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null)
scala> val c = new Array[Double](10)
c: Array[Double] = Array(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
未声明数据类型和已声明数据类型
未声明 Array类型,直接赋值,Array中是Any类型,即任何类型都可以
//当未声明数据类型时,写入了多种数据类型的数据,则生成的数组的数据类型为Any
scala> val d = Array("tom",1.21)
d: Array[Any] = Array(tom, 1.21)
//当未声明的数据类型时,写入同一种数据类型的数据,则生成对应类型的数组
scala> val e = Array("a","b","d")
e: Array[String] = Array(a, b, d)
//当已经声明数据类型时,写入对应类型数据
scala> val f:Array[Int] = Array(1,2,3,4)
f: Array[Int] = Array(1, 2, 3, 4)
//当已经声明数据类型时,写入多种数据类型的数据,会报错
scala> val f:Array[Int] = Array(1,2,3,1.1)
<console>:11: error: type mismatch;
found : Double(1.1)
required: Int
val f:Array[Int] = Array(1,2,3,1.1)
变长数组(ArrayBuffer)
变长数组在定义之前,需要先引入scala.collection.mutable._,否则会报错
//不引入scala.collection.mutable._,会报错
scala> val g = ArrayBuffer[Int]()
<console>:11: error: not found: value ArrayBuffer
val g = ArrayBuffer[Int]()
^
//引入scala.collection.mutable._,mutable代表可变
scala> import scala.collection.mutable._
import scala.collection.mutable._
//引入之后创建变长数组成功
scala> val g = ArrayBuffer[Int]()
g: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
//使用 += 往数组中添加数据
scala> g += 1
res7: g.type = ArrayBuffer(1)
//使用 += 往数组中添加多个数据
scala> g += (1,2,3,4)
res8: g.type = ArrayBuffer(1, 1, 2, 3, 4)
使用for,foreach遍历数组
scala> for(s <- g)println(s)
1
1
2
3
4
//推荐使用foreach
scala> g.foreach(println)
1
1
2
3
4
数组常见操作
scala> val myarray = Array(1,2,7,8,10,3,6)
myarray: Array[Int] = Array(1, 2, 7, 8, 10, 3, 6)
//取最大值
scala> myarray.max
res16: Int = 10
//取最小值
scala> myarray.min
res17: Int = 1
//降序排序
scala> myarray.sortWith(_>_)
res18: Array[Int] = Array(10, 8, 7, 6, 3, 2, 1)
//升序排序
scala> myarray.sortWith(_<_)
res19: Array[Int] = Array(1, 2, 3, 6, 7, 8, 10)
解释:myarray.sortWith(>)
完整:myarray.sortWith((a,b)=>{if(a>b) true else false})
(a,b)=>{if(a>b) true else false} 是匿名函数,没有名字,传入两个参数 a b,返回值是bool
sortWith(>) 是高阶函数,即参数是函数
多维数组
和Java一样,通过数组的数组来实现
//定义一个定长二维数组,ofDim代表在创建的时候直接打印
scala> val matrix = Array.ofDim[Int](3,4)
matrix: Array[Array[Int]] = Array(Array(0, 0, 0, 0), Array(0, 0, 0, 0), Array(0, 0, 0, 0))
//定义一个定长二维数组
scala> val matrix1 = Array[Int](3,4)
matrix1: Array[Int] = Array(3, 4)
//更改其中的一个值
scala> matrix(1)(2)=10
//打印出来
scala> matrix
res22: Array[Array[Int]] = Array(Array(0, 0, 0, 0), Array(0, 0, 10, 0), Array(0, 0, 0, 0))
//定义一个变长数组
scala> var triangle = new Array[Array[Int]](10)
triangle: Array[Array[Int]] = Array(null, null, null, null, null, null, null, null, null, null)
//打印初始值,Array初始值为null
scala> triangle
res23: Array[Array[Int]] = Array(null, null, null, null, null, null, null, null, null, null)
//往数组中插入数据
scala> for(i <- 0 until triangle.length)
| triangle(i)=new Array[Int](i+1)
//打印数组内容(下面的内容是手动换行的)
scala> triangle
res25: Array[Array[Int]] = Array(
Array(0),
Array(0, 0),
Array(0, 0, 0),
Array(0, 0, 0, 0),
Array(0, 0, 0, 0, 0),
Array(0, 0, 0, 0, 0, 0),
Array(0, 0, 0, 0, 0, 0, 0),
Array(0, 0, 0, 0, 0, 0, 0, 0),
Array(0, 0, 0, 0, 0, 0, 0, 0, 0),
Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0))