scala 基礎隨手記
scala 中和java不同的資料型別:
Unit | 表示無值,和其他語言中void等同。用作不返回任何結果的方法的結果型別。Unit只有一個例項值,寫成()。 |
Null | null 或空引用 |
Nothing | Nothing型別在Scala的類層級的最低端;它是任何其他型別的子型別。 |
Any | Any是所有其他類的超類 |
AnyRef | AnyRef類是Scala裡所有引用類(reference class)的基類 |
scala沒有java中的原生型別。在 scala 中是可以對數字等基礎型別呼叫方法的。
多行字串的表示方法
多行字串用三個雙引號來表示分隔符,格式為:""" ... """。
Scala 轉義字元
下表列出了常見的轉義字元:
轉義字元 | Unicode | 描述 |
---|---|---|
\b | \u0008 | 退格(BS) ,將當前位置移到前一列 |
\t | \u0009 | 水平製表(HT) (跳到下一個TAB位置) |
\n | \u000a | 換行(LF) ,將當前位置移到下一行開頭 |
\f | \u000c | 換頁(FF),將當前位置移到下頁開頭 |
\r | \u000d | 回車(CR) ,將當前位置移到本行開頭 |
\" | \u0022 | 代表一個雙引號(")字元 |
\' | \u0027 | 代表一個單引號(')字元 |
\\ | \u005c | 代表一個反斜線字元 '\' |
變數宣告
在學習如何宣告變數與常量之前,我們先來了解一些變數與常量。
- 一、變數: 在程式執行過程中其值可能發生改變的量叫做變數。如:時間,年齡。
- 二、常量 在程式執行過程中其值不會發生變化的量叫做常量。如:數值 3,字元'A'。
在 Scala 中,使用關鍵詞 "var" 宣告變數,使用關鍵詞 "val" 宣告常量。
宣告變數例項如下:
var myVar : String = "Foo"
var myVar : String = "Too"
以上定義了變數 myVar,我們可以修改它。
宣告常量例項如下:
val myVal : String = "Foo"
以上定義了常量 myVal,它是不能修改的。如果程式嘗試修改常量 myVal 的值,程式將會在編譯時報錯。
變數型別宣告
變數的型別在變數名之後等號之前宣告。
變數宣告一定需要初始值,否則會報錯。
變數型別引用
在 Scala 中宣告變數和常量不一定要指明資料型別,在沒有指明資料型別的情況下,其資料型別是通過變數或常量的初始值推斷出來的。
所以,如果在沒有指明資料型別的情況下宣告變數或常量必須要給出其初始值,否則將會報錯。
var myVar = 10;
val myVal = "Hello, Scala!";
以上例項中,myVar 會被推斷為 Int 型別,myVal 會被推斷為 String 型別。
Scala 多個變數宣告
Scala 支援多個變數的宣告:
val xmax, ymax = 100 // xmax, ymax都宣告為100
如果方法返回值是元組,我們可以使用 val 來宣告一個元組:
scala> val pa = (40,"Foo")
pa: (Int, String) = (40,Foo)
元組
Scala元組將固定數量的專案組合在一起,以便它們可以作為一個整體傳遞。 與陣列或列表不同,元組可以容納不同型別的物件,但它們也是不可變的。
以下是一個存有整數,字串和控制檯(console
)的元組的示例。
val t = (1, "hello", Console)
上面是以下語法的簡寫 -
val t = new Tuple3(1, "hello", Console)
元組的實際型別取決於它包含的數量和元素以及這些元素的型別。 因此,(99,"Luftballons")
的型別是Tuple2 [Int,String]
。 ('u','r',“the”,1,4,"me")
是Tuple6 [Char,Char,String,Int,Int,String]
。
元組是型別Tuple1
,Tuple2
,Tuple3
等等。目前在Scala中只能有22
個上限,如果您需要更多個元素,那麼可以使用集合而不是元組。
Scala定義了許多元素訪問方法。給定以下定義 -
val t = (4,3,2,1)
要訪問元組t
的元素,可以使用t._1
方法訪問第一個元素,t._2
方法訪問第二個元素,依此類推。 例如,以下表達式計算t
的所有元素的總和 -
val sum = t._1 + t._2 + t._3 + t._4
私有(Private)成員
用 private 關鍵字修飾,帶有此標記的成員僅在包含了成員定義的類或物件內部可見,同樣的規則還適用內部類。
class Outer{
class Inner{
private def f(){println("f")}
class InnerMost{
f() // 正確
}
}
(new Inner).f() //錯誤
}
(new Inner).f( ) 訪問不合法是因為 f 在 Inner 中被宣告為 private,而訪問不在類 Inner 之內。
但在 InnerMost 裡訪問 f 就沒有問題的,因為這個訪問包含在 Inner 類之內。
Java中允許這兩種訪問,因為它允許外部類訪問內部類的私有成員。
------------------------------------------------------------------------------------------------------------------------------------------------
保護(Protected)成員
在 scala 中,對保護(Protected)成員的訪問比 java 更嚴格一些。因為它只允許保護成員在定義了該成員的的類的子類中被訪問。而在java中,用protected關鍵字修飾的成員,除了定義了該成員的類的子類可以訪問,同一個包裡的其他類也可以進行訪問。
package p{
class Super{
protected def f() {println("f")}
}
class Sub extends Super{
f()
}
class Other{
(new Super).f() //錯誤
}
}
上例中,Sub 類對 f 的訪問沒有問題,因為 f 在 Super 中被宣告為 protected,而 Sub 是 Super 的子類。相反,Other 對 f 的訪問不被允許,因為 other 沒有繼承自 Super。而後者在 java 裡同樣被認可,因為 Other 與 Sub 在同一包裡。
---------------------------------------------------------------------------------------------------------------------------------------------------------------
for迴圈
語法
Scala 語言中 for 迴圈的語法:
for( var x <- Range ){
statement(s);
}
以上語法中,Range 可以是一個數字區間表示 i to j (包括j),或者 i until j(不包括j)。左箭頭 <- 用於為變數 x 賦值。
在 for 迴圈 中可以使用分號 (;) 來設定多個區間,它將迭代給定區間所有的可能值。以下例項演示了兩個區間的迴圈例項:
object Practice {
def main(args: Array[String]): Unit = {
var a = 0
var b = 0
for(a <- 1 to 3 ; b <- 1 to 3){
println("a = " + a)
println("b = " + b)
println("------------------")
}
}
}
a = 1
b = 1
------------------
a = 1
b = 2
------------------
a = 1
b = 3
------------------
a = 2
b = 1
------------------
a = 2
b = 2
------------------
a = 2
b = 3
------------------
a = 3
b = 1
------------------
a = 3
b = 2
------------------
a = 3
b = 3
------------------
for 迴圈集合
for 迴圈集合的語法如下:
for( var x <- List ){
statement(s);
}
以上語法中, List 變數是一個集合,for 迴圈會迭代所有集合的元素。
object Practice {
def main(args: Array[String]): Unit = {
var a = 0
val mylist = List(1,2,3,4,5)
for(a <- mylist){
println("a = " + a)
}
}
}
a = 1
a = 2
a = 3
a = 4
a = 5
for 迴圈過濾
Scala 可以使用一個或多個 if 語句來過濾一些元素。
以下是在 for 迴圈中使用過濾器的語法。
for( var x <- List
if condition1; if condition2...
){
statement(s);
可以使用分號(;)來為表示式新增一個或多個的過濾條件。
object Practice {
def main(args: Array[String]): Unit = {
var a = 0
val mylist = List(1,2,3,4,5,6,7,8,9,10)
for(a <- mylist
if a != 3 ; if a < 8){
println("a = " + a)
}
}
}
a = 1
a = 2
a = 4
a = 5
a = 6
a = 7
for 使用 yield
可以將 for 迴圈的返回值作為一個變數儲存。語法格式如下:
var retVal = for{ var x <- List
if condition1; if condition2...
}yield x
注意大括號中用於儲存變數和條件,retVal 是變數, 迴圈中的 yield 會把當前的元素記下來,儲存在集合中,迴圈結束後將返回該集合。
object Practice {
def main(args: Array[String]): Unit = {
var a = 0
val mylist = List(1,2,3,4,5,6,7,8,9,10)
val ret = for{a <- mylist//注意是大括號
if a != 3 ; if a < 8
}yield a
//輸出返回值
for(a <- ret){
println("a = " + a)
}
}
a = 1
a = 2
a = 4
a = 5
a = 6
a = 7
Scala 方法與函式
Scala 有方法與函式,二者在語義上的區別很小。Scala 方法是類的一部分,而函式是一個物件可以賦值給一個變數。換句話來說在類中定義的函式即是方法。
Scala 中的方法跟 Java 的類似,方法是組成類的一部分。
Scala 中的函式則是一個完整的物件,Scala 中的函式其實就是繼承了 Trait 的類的物件。
Scala 中使用 val 語句可以定義函式,def 語句定義方法。
class Test{
def m(x: Int) = x + 3
val f = (x: Int) => x + 3
}
方法宣告
Scala 方法宣告格式如下:
def functionName ([引數列表]) : [return type]
如果不寫等於號和方法主體,那麼方法會被隱式宣告為抽象(abstract),包含它的型別於是也是一個抽象型別。
方法定義
方法定義由一個 def 關鍵字開始,緊接著是可選的引數列表,一個冒號 : 和方法的返回型別,一個等於號 = ,最後是方法的主體。
Scala 方法定義格式如下:
def functionName ([引數列表]) : [return type] = {
function body
return [expr]
}
以上程式碼中 return type 可以是任意合法的 Scala 資料型別。引數列表中的引數可以使用逗號分隔。
以下方法的功能是將兩個傳入的引數相加並求和:
object add{
def addInt( a:Int, b:Int ) : Int = {
var sum:Int = 0
sum = a + b
return sum
}
}
如果方法沒有返回值,可以返回為 Unit,這個類似於 Java 的 void, 例項如下:
object Hello{
def printMe( ) : Unit = {
println("Hello, Scala!")
}
}
方法呼叫
Scala 提供了多種不同的方法呼叫方式:
以下是呼叫方法的標準格式:
functionName( 引數列表 )
如果方法使用了例項的物件來呼叫,我們可以使用類似java的格式 (使用 . 號):
[instance.]functionName( 引數列表 )
以上例項演示了定義與呼叫方法的例項:
object Practice {
def main(args: Array[String]): Unit = {
println("a+b=" + addInt(5,6))
}
def addInt (a:Int, b:Int): Int = {
var sum: Int = 0
sum = a + b
return sum
}
}
a+b=11
Scala 函式 - 可變引數
Scala 允許你指明函式的最後一個引數可以是重複的,即我們不需要指定函式引數的個數,可以向函式傳入可變長度引數列表。
Scala 通過在引數的型別之後放一個星號來設定可變引數(可重複的引數)。例如:
object Practice {
def main(args: Array[String]): Unit = {
printStrings("abc","def","ghi")
}
def printStrings(args: String*)={
var i = 0
for(arg <- args){
println("Arg value[" + i +"]:" + arg)
i = i +1
}
}
Arg value[0]:abc
Arg value[1]:def
Arg value[2]:ghi
Scala 遞迴函式
遞迴函式在函數語言程式設計的語言中起著重要的作用。
Scala 同樣支援遞迴函式。
遞迴函式意味著函式可以呼叫它本身。
以上例項使用遞迴函式來計算階乘:
object Practice {
def main(args: Array[String]): Unit = {
for (i <- 1 to 5){
println(i + "的階乘:" + factorial(i))
}
}
def factorial(n: Int) : BigInt={
if (n <= 1){
return 1
}
else
return n * factorial(n-1)
}
}
1的階乘:1
2的階乘:2
3的階乘:6
4的階乘:24
5的階乘:120
Scala 函式 - 預設引數值
Scala 可以為函式引數指定預設引數值,使用了預設引數,在呼叫函式的過程中可以不需要傳遞引數,這時函式就會呼叫它的預設引數值,如果傳遞了引數,則傳遞值會取代預設值。例項如下:
object Practice {
def main(args: Array[String]): Unit = {
println("返回值" + addInt())
println("------------------------------------")
println("返回值" + addInt(5,7))
}
def addInt(a:Int=8,b:Int=6) : Int={
var sum = 0
sum = a+b
return sum
}
}
返回值14
------------------------------------
返回值12
Scala 匿名函式
Scala 中定義匿名函式的語法很簡單,箭頭左邊是引數列表,右邊是函式體。
使用匿名函式後,我們的程式碼變得更簡潔了。
下面的表示式就定義了一個接受一個Int型別輸入引數的匿名函式:
var inc = (x:Int) => x+1
上述定義的匿名函式,其實是下面這種寫法的簡寫:
def add2 = new Function1[Int,Int]{
def apply(x:Int):Int = x+1;
}
以上例項的 inc 現在可作為一個函式,使用方式如下:
var x = inc(7)-1
同樣可以在匿名函式中定義多個引數:
var mul = (x: Int, y: Int) => x*y
mul 現在可作為一個函式,使用方式如下:
println(mul(3, 4))
我們也可以不給匿名函式設定引數,如下所示:
var userDir = () => { System.getProperty("user.dir") }
userDir 現在可作為一個函式,使用方式如下:
println( userDir() )
例項:
object Practice {
def main(args: Array[String]): Unit = {
println("返回值" + addInt(5,8))
}
//定義匿名函式
def addInt = (a:Int,b:Int) => a + b
}
返回值13
Scala 函式柯里化(Currying)
柯里化(Currying)指的是將原來接受兩個引數的函式變成新的接受一個引數的函式的過程。新的函式返回一個以原有第二個引數為引數的函式。
例項
首先我們定義一個函式:
def add(x:Int,y:Int)=x+y
那麼我們應用的時候,應該是這樣用:add(1,2)
現在我們把這個函式變一下形:
def add(x:Int)(y:Int) = x + y
那麼我們應用的時候,應該是這樣用:add(1)(2),最後結果都一樣是3,這種方式(過程)就叫柯里化。
實現過程
add(1)(2) 實際上是依次呼叫兩個普通函式(非柯里化函式),第一次呼叫使用一個引數 x,返回一個函式型別的值,第二次使用引數y呼叫這個函式型別的值。
實質上最先演變成這樣一個方法:
def add(x:Int)=(y:Int)=>x+y
那麼這個函式是什麼意思呢? 接收一個x為引數,返回一個匿名函式,該匿名函式的定義是:接收一個Int型引數y,函式體為x+y。現在我們來對這個方法進行呼叫。
val result = add(1)
返回一個result,那result的值應該是一個匿名函式:(y:Int)=>1+y
所以為了得到結果,我們繼續呼叫result。
val sum = result(2)
最後打印出來的結果就是3。
object Practice {
def main(args: Array[String]): Unit = {
val str1 = "hello,"
val str2 = "world"
println(strcat(str1)(str2))
}
def strcat(str1:String)(str2:String) = {
str1 + str2
}
}
hello,world
Scala 閉包
閉包是一個函式,返回值依賴於宣告在函式外部的一個或多個變數。
閉包通常來講可以簡單的認為是可以訪問一個函式裡面區域性變數的另外一個函式。
如下面這段匿名的函式:
val multiplier = (i:Int) => i * 10
函式體內有一個變數 i,它作為函式的一個引數。如下面的另一段程式碼:
val multiplier = (i:Int) => i * factor
在 multiplier 中有兩個變數:i 和 factor。其中的一個 i 是函式的形式引數,在 multiplier 函式被呼叫時,i 被賦予一個新的值。然而,factor不是形式引數,而是自由變數,考慮下面程式碼:
var factor = 3
val multiplier = (i:Int) => i * factor
這裡我們引入一個自由變數 factor,這個變數定義在函式外面。
這樣定義的函式變數 multiplier 成為一個"閉包",因為它引用到函式外面定義的變數,定義這個函式的過程是將這個自由變數捕獲而構成一個封閉的函式。
例項
object Practice {
def main(args: Array[String]): Unit = {
println("mult(2)= " + mult(2))
println("mult(3)= " + mult(3))
}
val factor = 2
// def mult(i:Int):Int={
// i * factor
// }
//也可用匿名函式
var mult = (i:Int)=>i*factor
}
mult(2)= 4
mult(3)= 6
Scala 字串
在 Scala 中,字串的型別實際上是 Java String,它本身沒有 String 類。
在 Scala 中,String 是一個不可變的物件,所以該物件不可被修改。這就意味著如果修改字串就會產生一個新的字串物件。
如果需要建立一個可以修改的字串,可以使用 String Builder 類,如下例項:
object Practice {
def main(args: Array[String]): Unit = {
var buf = new StringBuilder
buf += 'a'
buf ++= "bcd"
println("buf is " + buf.toString())
}
}
buf is abcd
字串連線
String 類中使用 concat() 方法來連線兩個字串:
string1.concat(string2);
例項
object Practice {
def main(args: Array[String]): Unit = {
val str1 = "abc"
val str2 = str1.concat("def")
println(str2)
}
}
abcdef
同樣也可以使用加號(+)來連線:
object Practice {
def main(args: Array[String]): Unit = {
val str1 = "scala 教程,"
val str2 = "大資料必備"
println(str1 + str2)
}
}
scala 教程,大資料必備
String 方法
下表列出了 java.lang.String 中常用的方法,可以在 Scala 中使用:
序號 | 方法及描述 |
---|---|
1 |
char charAt(int index) 返回指定位置的字元 |
2 |
int compareTo(Object o) 比較字串與物件 |
3 |
int compareTo(String anotherString) 按字典順序比較兩個字串 |
4 |
int compareToIgnoreCase(String str) 按字典順序比較兩個字串,不考慮大小寫 |
5 |
String concat(String str) 將指定字串連線到此字串的結尾 |
6 |
boolean contentEquals(StringBuffer sb) 將此字串與指定的 StringBuffer 比較。 |
7 |
static String copyValueOf(char[] data) 返回指定陣列中表示該字元序列的 String |
8 |
static String copyValueOf(char[] data, int offset, int count) 返回指定陣列中表示該字元序列的 String |
9 |
boolean endsWith(String suffix) 測試此字串是否以指定的字尾結束 |
10 |
boolean equals(Object anObject) 將此字串與指定的物件比較 |
11 |
boolean equalsIgnoreCase(String anotherString) 將此 String 與另一個 String 比較,不考慮大小寫 |
12 |
byte getBytes() 使用平臺的預設字符集將此 String 編碼為 byte 序列,並將結果儲存到一個新的 byte 陣列中 |
13 |
byte[] getBytes(String charsetName 使用指定的字符集將此 String 編碼為 byte 序列,並將結果儲存到一個新的 byte 陣列中 |
14 |
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 將字元從此字串複製到目標字元陣列 |
15 |
int hashCode() 返回此字串的雜湊碼 |
16 |
int indexOf(int ch) 返回指定字元在此字串中第一次出現處的索引 |
17 |
int indexOf(int ch, int fromIndex) 返回在此字串中第一次出現指定字元處的索引,從指定的索引開始搜尋 |
18 |
int indexOf(String str) 返回指定子字串在此字串中第一次出現處的索引 |
19 |
int indexOf(String str, int fromIndex) 返回指定子字串在此字串中第一次出現處的索引,從指定的索引開始 |
20 |
String intern() 返回字串物件的規範化表示形式 |
21 |
int lastIndexOf(int ch) 返回指定字元在此字串中最後一次出現處的索引 |
22 |
int lastIndexOf(int ch, int fromIndex) 返回指定字元在此字串中最後一次出現處的索引,從指定的索引處開始進行反向搜尋 |
23 |
int lastIndexOf(String str) 返回指定子字串在此字串中最右邊出現處的索引 |
24 |
int lastIndexOf(String str, int fromIndex) 返回指定子字串在此字串中最後一次出現處的索引,從指定的索引開始反向搜尋 |
25 |
int length() 返回此字串的長度 |
26 |
boolean matches(String regex) 告知此字串是否匹配給定的正則表示式 |
27 |
boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) 測試兩個字串區域是否相等 |
28 |
boolean regionMatches(int toffset, String other, int ooffset, int len) 測試兩個字串區域是否相等 |
29 |
String replace(char oldChar, char newChar) 返回一個新的字串,它是通過用 newChar 替換此字串中出現的所有 oldChar 得到的 |
30 |
String replaceAll(String regex, String replacement 使用給定的 replacement 替換此字串所有匹配給定的正則表示式的子字串 |
31 |
String replaceFirst(String regex, String replacement) 使用給定的 replacement 替換此字串匹配給定的正則表示式的第一個子字串 |
32 |
String[] split(String regex) 根據給定正則表示式的匹配拆分此字串 |
33 |
String[] split(String regex, int limit) 根據匹配給定的正則表示式來拆分此字串 |
34 |
boolean startsWith(String prefix) 測試此字串是否以指定的字首開始 |
35 |
boolean startsWith(String prefix, int toffset) 測試此字串從指定索引開始的子字串是否以指定字首開始。 |
36 |
CharSequence subSequence(int beginIndex, int endIndex) 返回一個新的字元序列,它是此序列的一個子序列 |
37 |
String substring(int beginIndex) 返回一個新的字串,它是此字串的一個子字串 |
38 |
String substring(int beginIndex, int endIndex) 返回一個新字串,它是此字串的一個子字串 |
39 |
char[] toCharArray() 將此字串轉換為一個新的字元陣列 |
40 |
String toLowerCase() 使用預設語言環境的規則將此 String 中的所有字元都轉換為小寫 |
41 |
String toLowerCase(Locale locale) 使用給定 Locale 的規則將此 String 中的所有字元都轉換為小寫 |
42 |
String toString() 返回此物件本身(它已經是一個字串!) |
43 |
String toUpperCase() 使用預設語言環境的規則將此 String 中的所有字元都轉換為大寫 |
44 |
String toUpperCase(Locale locale) 使用給定 Locale 的規則將此 String 中的所有字元都轉換為大寫 |
45 |
String trim() 刪除指定字串的首尾空白符 |
46 |
static String valueOf(primitive data type x) 返回指定型別引數的字串表示形式 |
Scala 陣列
Scala 語言中提供的陣列是用來儲存固定大小的同類型元素,陣列對於每一門編輯應語言來說都是重要的資料結構之一。
宣告陣列
以下是 Scala 陣列宣告的語法格式:
var z:Array[String] = new Array[String](3)
或
var z = new Array[String](3)
以上語法中,z 宣告一個字串型別的陣列,陣列長度為 3 ,可儲存 3 個元素。我們可以為每個元素設定值,並通過索引來訪問每個元素,如下所示:
z(0) = "Runoob"; z(1) = "Baidu"; z(4/2) = "Google"
我們也可以使用以下方式來定義一個數組:
var z = Array("Runoob", "Baidu", "Google")
處理陣列
陣列的元素型別和陣列的大小都是確定的,所以當處理陣列元素時候,我們通常使用基本的 for 迴圈。
以下例項演示了陣列的建立,初始化等處理過程:
object Practice {
def main(args: Array[String]): Unit = {
val mylist = Array(2.3,4.7,3.6,7.1,5.5)
println("列印元素")
for(a <- mylist){
println(a)
}
var sum = 0.0
for(i <- 0 until mylist.length){
sum += mylist(i)
}
println("和為 " + sum)
var max = 0.0
for(i <- 0 until mylist.length){
if (mylist(i) > max){
max = mylist(i)
}
}
println("最大值為 " + max )
}
}
列印元素
2.3
4.7
3.6
7.1
5.5
和為 23.2
最大值為 7.1
多維陣列
多維陣列一個數組中的值可以是另一個數組,另一個數組的值也可以是一個數組。矩陣與表格是我們常見的二維陣列。
以上是一個定義了二維陣列的例項:
var myMatrix = ofDim[Int](3,3)
例項中陣列中包含三個陣列元素,每個陣列元素又含有三個值。
合併陣列
以下例項中,我們使用 concat() 方法來合併兩個陣列,concat() 方法中接受多個數組引數:
import Array._
object Practice {
def main(args: Array[String]): Unit = {
val list1 = Array(1,2,3,4,5)
val list2 = Array(6,7,8,9,10)
val mylist = concat(list1,list2)
for(i <- 0 until mylist.length){
print(mylist(i) + " ")
}
}
}
1 2 3 4 5 6 7 8 9 10
建立區間陣列
以下例項中,使用了 range() 方法來生成一個區間範圍內的陣列。range() 方法最後一個引數為步長,預設為 1:
import Array._
object Practice {
def main(args: Array[String]): Unit = {
var arr1 = range(10,20,2)
var arr2 = range(10,20)
println("陣列1:")
for (i <- 0 until arr1.length){
print(arr1(i) + " ")
}
println()
println("陣列2:")
for (i <- 0 until arr2.length){
print(arr2(i) + " ")
}
}
}
陣列1:
10 12 14 16 18
陣列2:
10 11 12 13 14 15 16 17 18 19
Scala 陣列方法
下表中為 Scala 語言中處理陣列的重要方法,使用它前需要使用 import Array._ 引入包。
序號 | 方法和描述 |
---|---|
1 |
def apply( x: T, xs: T* ): Array[T] 建立指定物件 T 的陣列, T 的值可以是 Unit, Double, Float, Long, Int, Char, Short, Byte, Boolean。 |
2 |
def concat[T]( xss: Array[T]* ): Array[T] 合併陣列 |
3 |
def copy( src: AnyRef, srcPos: Int, dest: AnyRef, destPos: Int, length: Int ): Unit 複製一個數組到另一個數組上。相等於 Java's System.arraycopy(src, srcPos, dest, destPos, length)。 |
4 |
def empty[T]: Array[T] 返回長度為 0 的陣列 |
5 |
def iterate[T]( start: T, len: Int )( f: (T) => T ): Array[T] 返回指定長度陣列,每個陣列元素為指定函式的返回值。 以上例項陣列初始值為 0,長度為 3,計算函式為a=>a+1:
|
6 |
def fill[T]( n: Int )(elem: => T): Array[T] 返回陣列,長度為第一個引數指定,同時每個元素使用第二個引數進行填充。 |
7 |
def fill[T]( n1: Int, n2: Int )( elem: => T ): Array[Array[T]] 返回二陣列,長度為第一個引數指定,同時每個元素使用第二個引數進行填充。 |
8 |
def ofDim[T]( n1: Int ): Array[T] 建立指定長度的陣列 |
9 |
def ofDim[T]( n1: Int, n2: Int ): Array[Array[T]] 建立二維陣列 |
10 |
def ofDim[T]( n1: Int, n2: Int, n3: Int ): Array[Array[Array[T]]] 建立三維陣列 |
11 |
def range( start: Int, end: Int, step: Int ): Array[Int] 建立指定區間內的陣列,step 為每個元素間的步長 |
12 |
def range( start: Int, end: Int ): Array[Int] 建立指定區間內的陣列 |
13 |
def tabulate[T]( n: Int )(f: (Int)=> T): Array[T] 返回指定長度陣列,每個陣列元素為指定函式的返回值,預設從 0 開始。 以上例項返回 3 個元素:
|
14 |
def tabulate[T]( n1: Int, n2: Int )( f: (Int, Int ) => T): Array[Array[T]] 返回指定長度的二維陣列,每個陣列元素為指定函式的返回值,預設從 0 開始。 |
map操作和flatMap操作
map操作
map操作是針對集合的典型變換操作,它將某個函式應用到集合中的每個元素,併產生一個結果集合。
比如,給定一個字串列表,我們可以通過map操作對列表的中每個字串進行變換,讓每個字串都變成大寫字母,這樣變換後就可以得到一個新的集合。下面我們在Scala命令直譯器中,演示這個過程:
scala> val books = List("Hadoop", "Hive", "HDFS")
books: List[String] = List(Hadoop, Hive, HDFS)
scala> books.map(s => s.toUpperCase)
res0: List[String] = List(HADOOP, HIVE, HDFS)
至於下面的表示式:
s => s.toUpperCase
這種表示式被稱為“Lamda表示式”,在Java8以後有引入這種新的特性,Scala也擁有該特性。(備註:前面的“函數語言程式設計”內容有講到Lambda表示式)
“Lambda表示式”的形式如下:
(引數) => 表示式 //如果引數只有一個,引數的圓括號可以省略
可以看出,Lambda表示式實際上是一種匿名函式,大大簡化程式碼編寫工作。s => s.toUpperCase,它的含義是,對於輸入s,都都執行s.toUpperCase操作。
flatMap操作
flatMap是map的一種擴充套件。在flatMap中,我們會傳入一個函式,該函式對每個輸入都會返回一個集合(而不是一個元素),然後,flatMap把生成的多個集合“拍扁”成為一個集合。
下面我們在Scala直譯器中執行下面程式碼(下面同時包含了直譯器執行程式碼的反饋結果):
scala> val books = List("Hadoop","Hive","HDFS")
books: List[String] = List(Hadoop, Hive, HDFS)
scala> books flatMap (s => s.toList)
res0: List[Char] = List(H, a, o, o, p, H, i, v, e, H, D, F, S)
上面的flatMap執行時,會把books中的每個元素都呼叫toList,生成List[Char],最終,多個Char的集合被“拍扁”成一個集合。
這裡再補充說明一下:上面程式碼中books flatMap (s => s.toList)這種形式的程式碼,可以參考之前介紹過的:
a 方法 b
a.方法(b)
上面二者是等價的。所以:
books flatMap (s => s.toList)
books.flatMap(s => s.toList)
上面這二者也是等價的。
對於Lambda表示式“s => s.toList”,左側的s就是輸入引數,右側的s.toList表示對該引數要執行的操作。
所以:
books flatMap (s => s.toList)
這條語句的含義就是:對於列表books中的每個元素,都執行Lambda表示式定義的匿名函式“s => s.toList”,把一個books元素轉換成一個字元集合,比如說,把“Hadoop”這個字串轉換成字元集合List(‘H’,’a’,’d’,’o’,’o’,’p’),把“Hive”字串轉換成字元集合List(‘H’,’i’,’v’,’e’)。最後,flatMap把這些集合中的元素“拍扁”得到一個集合List(‘H’, ‘a’,’d’, ‘o’, ‘o’, ‘p’, ‘H’, ‘i’, ‘v’, ‘e’, ‘H’, ‘D’, ‘F’, ‘S’)。