一、Scala概述
scala是一門多范式編程語言,集成了面向對象編程和函數式編程等多種特性。
scala運行在虛擬機上,並兼容現有的Java程序。
Scala源代碼被編譯成java字節碼,所以運行在JVM上,並可以調用現有的Java類庫。
二、第一個Scala程序
Scala語句末尾的分號可寫可不寫
HelloSpark.scala
object HelloSpark{ def main(args:Array[String]):Unit = { println("Hello Spark!") } }
運行過程需要先進行編譯
編譯之后生成2個文件
運行HelloSpark.class
輸出結果Hello Spark
三、Scala的基本語法
1、概述
/** * Scala基本語法: * 區分大小寫 * 類名首字母大寫(MyFirstScalaClass) * 方法名稱第一個字母小寫(myMethodName()) * 程序文件名應該與對象名稱完全匹配 * def main(args:Array[String]):scala程序從main方法開始處理,程序的入口。 * * Scala注釋:分為多行/**/和單行// * * 換行符:Scala是面向行的語言,語句可以用分號(;)結束或換行符(println()) * * 定義包有兩種方法: * 1、package com.ahu * class HelloScala * 2、package com.ahu{ * class HelloScala * } * * 引用:import java.awt.Color * 如果想要引入包中的幾個成員,可以用selector(選取器): * import java.awt.{Color,Font} * // 重命名成員 * import java.util.{HashMap => JavaHashMap} * // 隱藏成員 默認情況下,Scala 總會引入 java.lang._ 、 scala._ 和 Predef._,所以在使用時都是省去scala.的 * import java.util.{HashMap => _, _} //引入了util包所有成員,但HashMap被隱藏了 */
2、Scala的數據類型
Scala 與 Java有着相同的數據類型,下表列出了 Scala 支持的數據類型:
數據類型 | 描述 |
---|---|
Byte | 8位有符號補碼整數。數值區間為 -128 到 127 |
Short | 16位有符號補碼整數。數值區間為 -32768 到 32767 |
Int | 32位有符號補碼整數。數值區間為 -2147483648 到 2147483647 |
Long | 64位有符號補碼整數。數值區間為 -9223372036854775808 到 9223372036854775807 |
Float | 32位IEEE754單精度浮點數 |
Double | 64位IEEE754單精度浮點數 |
Char | 16位無符號Unicode字符, 區間值為 U+0000 到 U+FFFF |
String | 字符序列 |
Boolean | true或false |
Unit | 表示無值,和其他語言中void等同。用作不返回任何結果的方法的結果類型。Unit只有一個實例值,寫成()。 |
Null | null 或空引用 |
Nothing | Nothing類型在Scala的類層級的最低端;它是任何其他類型的子類型。 |
Any | Any是所有其他類的超類 |
AnyRef | AnyRef類是Scala里所有引用類(reference class)的基類 |
Scala多行字符串的表示方式
var str = """ |第一行 |第二行 |第三行 """.stripMargin println(str)
3、Scala的變量
object VariableTest { def main(args: Array[String]) { //使用val定義的變量值是不可變的,相當於java里用final修飾的變量 val i = 1 //使用var定義的變量是可變的,在Scala中鼓勵使用val var s = "hello" //Scala編譯器會自動推斷變量的類型,必要的時候可以指定類型 //變量名在前,類型在后 val str: String = "world" } }
總結:
1)數據類型可以指定,也可以不指定,如果不指定,那么就會進行數據類型的推斷。
2)如果指定數據類型,數據類型的執行 方式是 在變量名后面寫一個冒號,然后寫上數據類型。
3)我們的scala里面變量的修飾符一共有兩個,一個是var 一個是val,如果是var修飾的變量,那么這個變量的值是可以修改的。如果是val修飾的變量,那么這個變量的值是不可以修改的。
4、Scala訪問修飾符
Scala訪問修飾符和Java基本一樣,分別有private、protected、public。
默認情況下,Scala對象的訪問級別是public。
(1)私有成員
用private關鍵字修飾的成員僅在包含了成員定義的類或對象內部可見。
class Outer { class Inner{ def start() = println("start") def end() = println("end") private def pause() = println("pause") } new Inner().start() new Inner().end() new Inner().pause() }
在上面的代碼里start和end兩個方法被定義為public類型,可以通過任意Inner實例訪問;pause被顯示定義為private,這樣就不能在Inner類外部訪問它。執行這段代碼,就會如注釋處聲明的一樣,會在該處報錯:
(2)protected
和私有成員類似,Scala的訪問控制比Java來說也是稍顯嚴格些。在 Scala中,由protected定義的成員只能由定義該成員和其派生類型訪問。而在 Java中,由protected定義的成員可以由同一個包中的其它類型訪問。在Scala中,可以通過其它方式來實現這種功能。
package p { class Super { protected def f(){println("f")} } class Sub extends Super { f() //OK } class Other { (new Super).f() //Error:f不可訪問 } }
(3)public
public訪問控制為Scala定義的缺省方式,所有沒有使用private和 protected修飾的成員(定義的類和方法)都是“公開的”,這樣的成員可以在任何地方被訪問。Scala不需要使用public來指定“公開訪問”修飾符。
注意:Scala中定義的類和方法默認都是public的,但在類中聲明的屬性默認是private的。
(4)作用保護域
作用域保護:Scala中,訪問修飾符可以通過使用限定詞強調。
private[x] 或者 protected[x]
private[x]:這個成員除了對[...]中的類或[...]中的包中的類及他們的伴生對象可見外,對其他的類都是private。
package bobsrockets { package navigation { //如果為private class Navigator,則類Navigator只會對當前包navigation中所有類型可見。 //即private默認省略了[X],X為當前包或者當前類或者當前單例對象。 //private[bobsrockets]則表示將類Navigator從當前包擴展到對bobsrockets包中的所有類型可見。 private[bobsrockets] class Navigator { protected[navigation] def useStarChart() {} class LegOfJourney { private[Navigator] val distance = 100 } private[this] var speed = 200 } } package launch { import navigation._ object Vehicle { //private val guide:表示guide默認被當前單例對象可見。 //private[launch] val guide:表示guide由默認對當前單例對象可見擴展到對launch包中的所有類型可見。 private[launch] val guide = new Navigator } } }
在這個例子中,類Navigator使用 private[bobsrockets] 來修飾,這表示這個類可以被bobsrockets包中所有類型訪問,比如通常情況下 Vehicle無法訪問私有類型Navigator,但使用包作用域之后,Vechile 中可以訪問Navigator。
5、Scala運算符
與Java一樣,不過Scala的運算符實際上是一種方法。
6、條件表達式
Scala的的條件表達式比較簡潔,例如:
def main(args: Array[String]): Unit = { val x = 1 //判斷x的值,將結果賦給y val y = if (x > 0) 1 else -1 //打印y的值 println("y=" + y) //支持混合類型表達式 val z = if (x > 1) 1 else "error" //打印z的值 println("z=" + z) //如果缺失else,相當於if (x > 2) 1 else () val m = if (x > 2) 1 println("m=" + m) //在scala中每個表達式都有值,scala中有個Unit類,寫做(),相當於Java中的void val n = if (x > 2) 1 else () println("n=" + n) //if和else if val k = if (x < 0) 0 else if (x >= 1) 1 else -1 println("k=" + k) }
運行結果
總結:
1)if條件表達式它是有返回值的
2)返回值會根據條件表達式的情況會進行自動的數據類型的推斷。
7、塊表達式
def main(args: Array[String]): Unit = { val x = 0 val result = { if(x < 0) 1 else if(x >= 1) -1 else "error" } println(result) }
運行結果
8、循環
(1)while循環
def main(args: Array[String]): Unit = { var n = 10 while ( { n > 0 }) { println(n) n -= 1 } }
總結:
1)while使用跟java一模一樣
2)注意點:在scala里面不支持 i++ i-- 等操作
統一寫成 i-=1
(2)for循環
在scala中有for循環和while循環,用for循環比較多
for循環語法結構:
for (i <- 表達式/數組/集合)
def main(args: Array[String]): Unit = { //for(i <- 表達式),表達式1 to 10返回一個Range(區間) //每次循環將區間中的一個值賦給i for (i <- 1 to 10) print(i+"\t") //for(i <- 數組) println() val arr = Array("a", "b", "c") for (i <- arr) println(i) //高級for循環 //每個生成器都可以帶一個條件,注意:if前面沒有分號 for(i <- 1 to 3; j <- 1 to 3 if i != j) print((10 * i + j) + " ") println() //for推導式:如果for循環的循環體以yield開始,則該循環會構建出一個集合 //每次迭代生成集合中的一個值 val v = for (i <- 1 to 10) yield i * 10 println(v) }
運行結果
總結:
1)在scala里面沒有運算符,都有的符號其實都是方法。
2)在scala里面沒有++ -- 的用法
3)for( i <- 表達式/數組/集合)
4)在for循環里面我們是可以添加if表達式
5)有兩個特殊表達式需要了解:
To 1 to 3 1 2 3
Until 1 until 3 12
6)如果在使用for循環的時候,for循環的時候我們需要獲取,我們可以是使用yield關鍵字。
9、方法和函數
(1)定義方法
方法的返回值類型可以不寫,編譯器可以自動推斷出來,但是對於遞歸函數,必須指定返回類型。
如果不寫等號,代表沒有返回值。
(2)定義函數
(3)方法和函數的區別
在函數式編程語言中,函數是“頭等公民”,它可以像任何其他數據類型一樣被傳遞和操作
案例:首先定義一個方法,再定義一個函數,然后將函數傳遞到方法里面
object TestScala { //定義一個方法 //方法m2參數要求是一個函數,函數的參數必須是兩個Int類型 //返回值類型也是Int類型 def m1(f:(Int,Int) => Int) : Int = { f(2,6) } //定義一個函數f1,參數是兩個Int類型,返回值是一個Int類型 val f1 = (x:Int,y:Int) => x+y //再定義一個函數f2 val f2 = (m:Int,n:Int) => m*n //main方法 def main(args: Array[String]): Unit = { //調用m1方法,並傳入f1函數 val r1 = m1(f1) println("r1="+r1) //調用m1方法,並傳入f2函數 val r2 = m1(f2) println("r2="+r2) } }
(4)將方法轉換成函數