Scala學習日誌——一切從使用開始
摘要
Scala,被稱為可伸展的語言。由於其的完全面向物件性卻又融合函數語言程式設計,使其程式碼十分優美,簡潔。他可以用寥寥幾行就完成在Java中大量程式碼才能完成的操作。且簡單易懂,有效的增強程式碼的可讀性,並減少出錯的可能。由於近年來大資料方便Spark一片大好,可以說學大資料必須要學Spark。而總所周知的,Spark的底層是由Scala進行編寫的,因此Spark對Scala的適應性是十分好的。因此學習Spark必須先學Scala。不例外的,我也走上了這條道路。
基本中的基本
我不願意將scala吹得天花亂墜,這裡主要是一些小的實踐來明確scala究竟是如何用的,更深的東西,等能用了再慢慢研究。
1、定義一些變數
首先,我是從java轉向scala的,因此當我使用val時,感覺十分的彆扭。不過同理,如果你是從函數語言程式設計語言轉入scala的,你同樣會覺得var的使用簡直就是中褻瀆。這裡,無論你是從什麼語言轉向scala,我都建議你多使用val,儘量能夠達到整個程式中不出現var。為什麼這麼說,我一個小例子來進行說明:
//宣告函式語法:def 函式名(引數1:引數型別):返回值型別=
def printArgs(args: Array[String]): Unit = {
var i = 0
while (i < args.length) {
i += 1
}
}
這個方法是使用var 並因此屬於指令式風格
def printArgs(args: Array[String]): Unit = {
for (arg <- args)
println(arg)
}
這是沒有使用var的,更函式式。可以簡單的看出,不使用var令程式碼更加的簡單易懂,減少了出錯的可能。
2. 使用Array與ArrayBuffer
- 宣告定長陣列:
val arr=Array(1,2,3,4) //arr這時為 Array(1,2,3,4)
如果要宣告一個空的陣列,可以使用:
val arr2=new Array[Int]
Array排序
println(util.Sorting.quickSort(a))
呼叫陣列的方法:
arr2(0)="3" //修改arr2(0)的值,注意使用的是()而不是[]
很多時候,我們並不確定陣列的長度。亦或許我們要向陣列中新增元素,這時就需要可變長的陣列,在java中,有ArrayList,scala中則是ArrayBuffer。下面是一些ArrrayBuffer的使用方法,註釋寫得挺詳細的,我便不贅述了。
//變長陣列:ArrayBuffer
val b=ArrayBuffer[Int]() //宣告
val c=new ArrayBuffer[Int]()
/*
高效操作
*/
//在ArrayBuffer後新增一個元素
b += 1;
for(i <- b) println(i)
//新增多個元素
b += (3,5,7,9)
println(b)
//新增任意集合
b ++= Array(2,4,6,8)
println(b)
//移除元素
b.trimEnd(3)
println(b)
b.trimStart(3)
println(b)
/*
並不那麼高效的操作
*/
//在下標2前插入6
b.insert(2,6)
println(b)
b.insert(2,7,8,9) //下標2前插入多個數據
//移除元素
b.remove(2) //移除下標2
b.remove(2,3) //第二個引數表示要移除多少元素
for(i <- 0 until (b.length,2)) println(b(i)) //兩個一跳
for(i <- (0 until b.length).reverse) println(b(i)) //從後向前迴圈
//移除陣列中第一個負數之外的所有負數
val a=Array(1,-1,3,-3,-5,-7,3,4,6,8)
//首先取到所有不被移除的下標
var first=true
val indexs = for(i<- 0 until a.length if first || a(i)>= 0) yield{
if( a(i)<0 )first=false ; i
}
println(indexs)
//將元素向前移動,再去掉尾部
for(j <- 0 until indexs.length ) {
a(j)=a(indexs(j))
a.toBuffer.trimEnd(a.length-indexs.length)
}
for(i <- a ) print(i+"\t")
println()
println(a.sum+" "+a.max+" "+a.min) //sum輸出整個陣列的和(必須是數值型別 ),max最大,min最小值,不用非是數值
//陣列排序
//ArrayBuffer排序
println(b.sorted)
val c=ArrayBuffer(1,2,3,4,5,6,7,8,9)
println(c.sortWith(_>_)) //自己給定演算法
- Array與ArrayBuffer之間可以自由轉換。比如上面例子中c.toArray便可將c轉化為Array,b.toBuffer便可將b轉化為ArrayBuffer。因此當不確定陣列長度時,可以先使用ArrayBuffer,操作完成後,再轉換回Array便可。
3、宣告函式
宣告函式沒什麼可說的,直接上程式碼了,註釋同樣挺詳細的
//宣告函式語法:def 函式名(引數1:引數型別):返回值型別=
def printArgs(args: Array[String]): Unit = {
var i = 0
while (i < args.length) {
i += 1
}
}
//函式引數可以有預設值,不過呼叫時如果傳入引數的話就會替代。
def decorate(str: String, left: String = "[", right: String = "]") = left + str + right
//變長引數函式:可以傳入不定量的引數,但是不代表著可以傳入該引數的陣列
def sum(args : Int*): Int ={
var result = 0
for(arg <- args) result += arg
result
}
//遞迴呼叫
def recursiveSum(args : Int*) :Int={
if(args.length == 0) 0
else args.head + recursiveSum(args.tail:_*)
//tail是所有其他元素的序列,使用:_*來將它轉化為引數序列
}
4、控制語句
類似if,while這些我認為沒有太大說的必要。怎麼使用其實很簡單,這裡我只重點說說for迴圈,因為小生認為scala的for迴圈十分的強大且優美:
for(i <- 0 to 3) println(i)
//for迴圈中可以很複雜,可以有多個引數,實際就像java中的兩層迴圈,一層是i,一層是j。
//i <- 0 to 3的意思是i遍歷0到3
//scala的for迴圈中還能加 if 只有能滿足 if 的才會被遍歷到
for (i <- 0 to 3; j <- 0 to 3 if (i != 0 && i != j)) print(decorate((i * 10 + j).toString, "<<", ">>") + " ")
//輸出<<10>> <<12>> <<13>> <<20>> <<21>> <<23>> <<30>> <<31>> <<32>>
//還有一種for迴圈推到式,當在for迴圈開頭使用yield時,
// 會生成一個集合,然後將每個迴圈到的值放入集合
val a=for (i <- 0 to 3; j <- 0 to 3 if (i != 0 && i != j)) yield decorate((i * 10 + j).toString, "<<", ">>")
//a=Vector(<<10>>, <<12>>, <<13>>, <<20>>, <<21>>, <<23>>, <<30>>, <<31>>, <<32>>)
5、map,tuple
map對映是一種特殊的tuple,這裡我只說說他們的用法。同樣在程式碼裡:
- map的用法:
//構造map
val scores = Map("wrm" -> 21,"wln" -> 21,"xxw" -> 11)
//預設構造的是不可變的Map,如需要可變的Map,使用:
val scores1 =scala.collection.mutable.Map("wrm" -> 21,"wln" -> 21,"xxw" -> 11)
//如果想先建立一個空的map,需要指定一個Map實現(new) 和給出型別引數
val nullmap=new HashMap[String,Int]
println(scores)
//通過鍵找到值:
println(scores("wrm"))
//判斷是否有某個值,有便獲得
val hasValue=if(scores.contains("zzz")) scores("zzz") else 0
println(hasValue)
//有種便捷的寫法:
val simplaValue=scores.getOrElse("xxw",0)
println(simplaValue)
//map的更新
//更新某個對映的值:= 如果存在就更新,不存在就新增
scores1("xxw")=100
scores1("yxs")=30
println(scores1)
//+=用來新增多個關係
scores1+=("yjl" -> 22,"wzx" ->21)
println(scores1)
//-=用來移除某個關係
scores1-=("yxs")
println(scores1)
//上述是對於可變MAP(scala.collection.mutable.Map)
//對於不可變map,可以這樣操作,
val newmap=scores + ("wrm" -> 23,"wzx" ->21) //跟新過的map,如果key存在就更新,不存在就新增
println(newmap)
//其餘操作同理,看似建立了過多的val效率低又浪費資源,其實並非如此——老的對映和新的對映共享大部分資源。(因為他們是不可變的!)
//map的迭代:
//十分簡單的一個方式
for((k,v) <- newmap) println("key:"+k+" value:"+v)
//要反轉一個對映——交換k,v位置,可用
val changeMap=for((k,v) <- newmap) yield (v,k)
println(changeMap )
- tunple的用法
//Tuple的每個引數的資料型別都是不同的如:
val t=(1,3.14,"Fred")
//可以使用t._1,t._2或t _1,t _2來進行呼叫
println(t _2) //3.14
//可以通過模式匹配來使用Tuple
val (first,second,third)=t
println(first+"\t"+second+"\t"+third) //1 3.14 Fred
//在不需要匹配所有項時,不需匹配的項可以使用_忽略
val (a,b,_)=t
println(a+"\t"+b) //1 3.14
//拉鍊操作
val symbols=Array("<","-",">")
val counts=Array(2,10,2)
//可以將兩個Array壓縮為一個Tuple
val pairs=symbols.zip(counts)
//這些對偶可以被一起處理
for((s,n) <- pairs) Console.print(s * n) //<<---------->>
今天就進行到這裡,接下來會進行更加深入的研究學習。希望這篇部落格能幫到有需要的朋友!