scala学习 之 及 基本和高级用法(二)
目錄
1. Scala的數據類型
2. Scala變量
3. Scala 訪問修飾符
4. Scala 方法和函數
5. Scala數組
6. Collection(集合)
7. Scala的類和對象
8. Scala的接口trait
9. Scala的模式匹配
10. Scala的正則匹配
11. 異常處理
12. 提取器
13. Scala的文件I/O
14. 偏函數
1. Scala的數據類型
比Java多出的數據類型有:
Unit: 表示無值,和其他語言中void等同。用作不返回任何結果的方法的結果類型。Unit只有一個實例值,寫成()。
Nothing Nothing類型在Scala的類層級的最低端;它是任何其他類型的子類型。
Nothing :Nothing類型在Scala的類層級的最低端;它是任何其他類型的子類型。
Any :Any是所有其他類的超類
AnyRef :AnyRef類是Scala里所有引用類(reference class)的基類
多行字符串的表示方法:
多行字符串用三個雙引號來表示分隔符,格式為:”“” … “”“。
2. Scala變量
在 Scala 中,使用關鍵詞 “var” 聲明變量,使用關鍵詞 “val” 聲明常量。
var myVar : String = "Foo" var myVar : String = "Too"在 Scala 中聲明變量和常量不一定要指明數據類型,在沒有指明數據類型的情況下,其數據類型是通過變量或常量的初始值推斷出來的。
var myVar = 10; val myVal = "Hello, Scala!";3. Scala 訪問修飾符
Scala 訪問修飾符有:private,protected,public。
如果沒有指定訪問修飾符符,默認情況下,Scala 對象的訪問級別都是 public。
Scala 中的 private 限定符,比 Java 更嚴格,在嵌套類情況下,外層類甚至不能訪問被嵌套類的私有成員。
在 scala 中,對保護(Protected)成員的訪問比 java 更嚴格一些。因為它只允許保護成員在定義了該成員的的類的子類中被訪問。而在java中,用protected關鍵字修飾的成員,除了定義了該成員的類的子類可以訪問,同一個包里的其他類也可以進行訪問。
作用域保護:
private[x] protected[x]這里的x指代某個所屬的包、類或單例對象。如果寫成private[x],讀作”這個成員除了對[…]中的類或[…]中的包中的類及它們的伴生對像可見外,對其它所有類都是private。
4. Scala 方法和函數
Scala 有方法與函數,二者在語義上的區別很小。Scala 中的方法跟 Java 的類似,方法是組成類的一部分。Scala 中的函數則是一個完整的對象,Scala 中的函數其實就是繼承了 Trait 的類的對象。
Scala 中使用 val 語句可以定義函數,def 語句定義方法。
方法的定義:
def functionName ([參數列表]) : [return type] = {function bodyreturn [expr] }object add{def addInt( a:Int, b:Int ) : Int = {var sum:Int = 0sum = a + breturn sum} }Scala 函數傳名調用(call-by-name)
Scala的解釋器在解析函數參數(function arguments)時有兩種方式:
傳值調用(call-by-value):先計算參數表達式的值,再應用到函數內部;
傳名調用(call-by-name):將未計算的參數表達式直接應用到函數內部
在進入函數內部前,傳值調用方式就已經將參數表達式的值計算完畢,而傳名調用是在函數內部進行參數表達式的值計算的。這就造成了一種現象,每次使用傳名調用時,解釋器都會計算一次表達式的值。
object Test {def main(args: Array[String]) {delayed(time());}def time() = {println("獲取時間,單位為納秒")System.nanoTime}def delayed( t: => Long ) = {println("在 delayed 方法內")println("參數: " + t)t} } 在 delayed 方法內 獲取時間,單位為納秒 參數: 241550840475831 獲取時間,單位為納秒指定函數參數名
object Test {def main(args: Array[String]) {printInt(b=5, a=7);}def printInt( a:Int, b:Int ) = {println("Value of a : " + a );println("Value of b : " + b );} } Value of a : 7 Value of b : 5默認參數值
object Test {def main(args: Array[String]) {println( "返回值 : " + addInt() );}def addInt( a:Int=5, b:Int=7 ) : Int = {var sum:Int = 0sum = a + breturn sum} } $ scalac Test.scala $ scala Test 返回值 : 12可變參數
object Test {def main(args: Array[String]) {printStrings("Runoob", "Scala", "Python");}def printStrings( args:String* ) = {var i : Int = 0;for( arg <- args ){println("Arg value[" + i + "] = " + arg );i = i + 1;}} } Arg value[0] = Runoob Arg value[1] = Scala Arg value[2] = PythonScale函數嵌套
object Test {def main(args: Array[String]) {println( factorial(0) )println( factorial(1) )println( factorial(2) )println( factorial(3) )}def factorial(i: Int): Int = {def fact(i: Int, accumulator: Int): Int = {if (i <= 1)accumulatorelsefact(i - 1, i * accumulator)}fact(i, 1)} } 1 1 2 6偏應用函數
import java.util.Dateobject Test {def main(args: Array[String]) {val date = new Datelog(date, "message1" )Thread.sleep(1000)log(date, "message2" )Thread.sleep(1000)log(date, "message3" )}def log(date: Date, message: String) = {println(date + "----" + message)} }我們使用偏應用函數優化以上方法,綁定第一個 date 參數,第二個參數使用下劃線(_)替換缺失的參數列表
import java.util.Dateobject Test {def main(args: Array[String]) {val date = new Dateval logWithDateBound = log(date, _ : String)logWithDateBound("message1" )Thread.sleep(1000)logWithDateBound("message2" )Thread.sleep(1000)logWithDateBound("message3" )}def log(date: Date, message: String) = {println(date + "----" + message)} }高階函數
高階函數(Higher-Order Function)就是操作其他函數的函數。
object Test {def main(args: Array[String]) { println( apply( layout, 10) )}// 函數 f 和 值 v 作為參數,而函數 f 又調用了參數 vdef apply(f: Int => String, v: Int) = f(v)def layout[A](x: A) = "[" + x.toString() + "]"} [10]匿名函數
匿名函數箭頭左邊是參數列表,右邊是函數體。
var inc = (x:Int) => x+1inc 現在可作為一個函數,使用方式如下
var x = inc(7)-1我們也可以不給匿名函數設置參數,如下所示:
var userDir = () => { System.getProperty("user.dir") }函數柯里化(Currying)
柯里化(Currying)指的是將原來接受兩個參數的函數變成新的接受一個參數的函數的過程。新的函數返回一個以原有第二個參數為參數的函數。
def add(x:Int,y:Int)=x+y //柯里化 def add(x:Int)(y:Int) = x + y5. Scala數組
初始化方式:
var z:Array[String] = new Array[String](3) var z = new Array[String](3) var z = Array("Runoob", "Baidu", "Google")遍歷數組
object Test {def main(args: Array[String]) {var myList = Array(1.9, 2.9, 3.4, 3.5)// 輸出所有數組元素,x代表值for ( x <- myList ) {println( x )}// 計算數組所有元素的總和,i代表索引var total = 0.0;for ( i <- 0 to (myList.length - 1)) {total += myList(i);}println("總和為 " + total);} }合并數組
object Test {def main(args: Array[String]) {var myList1 = Array(1.9, 2.9, 3.4, 3.5)var myList2 = Array(8.9, 7.9, 0.4, 1.5)var myList3 = concat( myList1, myList2)} }創建區間數組
//range() 方法最后一個參數為步長,默認為 1import Array._object Test {def main(args: Array[String]) {var myList1 = range(10, 20, 2)var myList2 = range(10,20)// 輸出所有數組元素for ( x <- myList1 ) {print( " " + x )}println()for ( x <- myList2 ) {print( " " + x )}} }6. Collection(集合)
// 定義整型 List val x = List(1,2,3,4)// 定義 Set val x = Set(1,3,5,7)// 定義 Map val x = Map("one" -> 1, "two" -> 2, "three" -> 3)// 創建兩個不同類型元素的元組 val x = (10, "Runoob")// 定義 Option val x:Option[Int] = Some(5)List的操作
在官方文檔中List是immutable的,所以對List的所謂增上改查都是產生新的對象,并非在原來的集合上改動
遍歷(跟數組的遍歷方法一樣)
val a = List(1,2,3,4)//for (i <- a) println(i)//for (i <- 0 to a.length-1) println(a(i))a.foreach { x => print(x +" ")} println(a.mkString(" ")) //mkString方法適合輸出對單個元素的操作
var list = List("scala","spark","hadoop") "test"::list // 添加到元素首對象 (返回新對象,源對象不變) list ::= "test"list(0) //取 list apply 0 list.last //最后一個 list.tail //list = list.updated(2,"hadoop1") // 返回新對象,源對象不變lsit = list.drop(3);//從左邊丟掉3個元素 lsit = list.dropRight(3)對集合的基本操作
++ :[B](that: GenTraversableOnce[B]): List[B] 從列表的尾部添加另外一個列表 ++: :[B >: A, That](that: collection.Traversable[B])(implicit bf: CanBuildFrom[List[A], B, That]): That 在列表的頭部添加一個列表+: :(elem: A): List[A] 在列表的頭部添加一個元素 :+ :(elem: A): List[A] 在列表的尾部添加一個元素對集合的驚人操作
求一個List的最大值
val num = List(11,2,5,1,6) println(num.max);//根據書的頁數排序 class Book(title:String, pages:Int) val books = Seq(Book("Future of Scala developers", 85),Book("Parallel algorithms", 240),Book("Object Oriented Programming", 130),Book("Mobile Development", 495) ) books.maxBy(book => book.pages)過濾集合元素
val numbers = Seq(1,2,3,4,5,6,7,8,9,10) numbers.filter(n => n % 2 == 0)//獲取頁數大于120頁的書 class Book(title:String, pages:Int) val books = Seq(Book("Future of Scala developers", 85),Book("Parallel algorithms", 240),Book("Object Oriented Programming", 130),Book("Mobile Development", 495) ) books.filter(book => book.pages >= 120)filterNot方法與filter方法相反展開嵌套結構
scala> List(List(1, 2), List(3, 4)).flatten res0: List[Int] = List(1, 2, 3, 4)歐拉圖函數
歐拉圖函數就是差集、交集和并集
val num1 = Seq(1, 2, 3, 4, 5, 6) val num2 = Seq(4, 5, 6, 7, 8, 9)//List(1, 2, 3) num1.diff(num2)//List(4, 5, 6) num1.intersect(num2)//List(1, 2, 3, 4, 5, 6, 4, 5, 6, 7, 8, 9) num1.union(num2)//List(1, 2, 3, 4, 5, 6, 7, 8, 9) num1.union(num2).distinctmap函數
map函數遍歷集合中的元素并對每個元素調用函數
val numbers = Seq(1,2,3,4,5,6)//List(2, 4, 6, 8, 10, 12) numbers.map(n => n * 2)val chars = Seq('a', 'b', 'c', 'd')//List(A, B, C, D) chars.map(ch => ch.toUpper)flatMap函數
flatMap 是由下列這兩個函數組成的:map & flatten
val abcd = Seq('a', 'b', 'c', 'd')//List(A, a, B, b, C, c, D, d) abcd.flatMap(ch => List(ch.toUpper, ch))對整個集合進行條件檢查
集合的元素有哪怕一個元素不符合條件,就返回false
val numbers = Seq(3, 7, 2, 9, 6, 5, 1, 4, 2)//ture numbers.forall(n => n < 10)//false numbers.forall(n => n > 5)集合分組
val numbers = Seq(3, 7, 2, 9, 6, 5, 1, 4, 2)//(List(2, 6, 4, 2), List(3, 7, 9, 5, 1)) (part1,part2) = numbers.partition(n => n % 2 == 0)fold和reduce
reduce就是以第一個元素為初始值,依次對后面的元素進行操作
fold就是在第一對括號中,放一個起始值,在第二對括號中,我們定義需要對數字序列的每個元素執行的操作。
排序
object Test {def main(args: Array[String]) {val p = List(2,5,23,3,4);var s = p.sortWith(_<_)println(s.mkString(" ")) //23 5 4 3 2} }7. Scala的類和對象
我們可以使用 new 關鍵字來創建類的對象,實例如下:
class Point(xc: Int, yc: Int) {var x: Int = xcvar y: Int = ycdef move(dx: Int, dy: Int) {x = x + dxy = y + dyprintln ("x 的坐標點: " + x);println ("y 的坐標點: " + y);} }類的繼承
- 重寫一個非抽象方法必須使用override修飾符。
- 只有主構造函數才可以往基類的構造函數里寫參數。
- 在子類中重寫超類的抽象方法時,你不需要使用override關鍵字。
scala的單例模式
在Scala中,是沒有static這個東西的,但是它也為我們提供了單例模式的實現方法,那就是 object,
Scala中使用單例模式時,除了定義的類之外,還要定義一個同名的object對象,它和類的區別是,object對象不能帶參數。
使用
//定義一個單例對象 val test = StaticTest //調用add方法 println(test.add(2,3))8. Scala的接口trait
Scala Trait(特征) 相當于 Java 的接口,與接口不同的是,它還可以定義屬性和方法的實現。
類繼承Trait后,必須實現其中的抽象方法,實現時不需要使用override關鍵字,同時Scala同Java一樣,不支持類多繼承,但支持多重繼承Trait,使用with關鍵字即可。
trait Equal {//沒有定義方法的實現def isEqual(x: Any): Boolean//定義了方法的實現def isNotEqual(x: Any): Boolean = !isEqual(x) }class Point(xc: Int, yc: Int) extends Equal {var x: Int = xcvar y: Int = ycdef isEqual(obj: Any) =obj.isInstanceOf[Point] &&obj.asInstanceOf[Point].x == x }Trait高級
結果:
做準備 做三明治 完成了- 父類的構造函數
- Trait的構造代碼執行,多個Trait從左向右依次執行
- 構造Trait時會先構造父Trait,如果多個Trait繼承同一個父Trait,則父Trait只會構造一次
- 所有trait構造結束之后,子類的構造函數執行
結果:
this is People's class Constructor this is cloth's trail Constructor this is pant's trail Constructor this is Man's class Constructor9. Scala的模式匹配
match 對應 Java 里的 switch,但是寫在選擇器表達式之后。即: 選擇器 match {備選項}。
def matchTest(x: Any): Any = x match {case 1 => "one"case "two" => 2case y: Int => "scala.Int"case _ => "many"}比較對象
object Test {def main(args: Array[String]) {val alice = new Person("Alice", 25)val bob = new Person("Bob", 32)val charlie = new Person("Charlie", 32)for (person <- List(alice, bob, charlie)) {person match {case Person("Alice", 25) => println("Hi Alice!")case Person("Bob", 32) => println("Hi Bob!")case Person(name, age) =>println("Age: " + age + " year, name: " + name + "?")}}}// 樣例類case class Person(name: String, age: Int) }處理異常
def processException(e: Exception) {e match {case e1: IllegalArgumentException => println("you have illegal arguments! exception is: " + e1)case e2: FileNotFoundException => println("cannot find the file you need read or write!, exception is: " + e2)case e3: IOException => println("you got an error while you were doing IO operation! exception is: " + e3)case _: Exception => println("cannot know which exception you have!" )} }Scala有一種特殊的類型,叫做Option。Option有兩種值,一種是Some,表示有值,一種是None,表示沒有值。
Option通常會用于模式匹配中,用于判斷某個變量是有值還是沒有值,這比null來的更加簡潔明了
Option的用法必須掌握,因為Spark源碼中大量地使用了Option,比如Some(a)、None這種語法,因此必須看得懂Option模式匹配,才能夠讀懂spark源碼。
10. Scala的正則匹配
完全匹配
val pattern = "^[a-z0-9._%\\-+]+@(?:[a-z0-9\\-]+\\.)+[a-z]{2,4}$" val emailRegex = pattern.r // r()方法將字符串轉化成Regex對象 emailRegex.pattern.matcher("tt@16.cn").matches // true查找匹配部分
object Test {def main(args: Array[String]) {val p = "[0-9]+".rvar s = p.findAllIn("2 ad 12ab ab21 23").toList // List(2, 12, 21, 23)var k = p.findFirstMatchIn("abc123xyz") // scala.util.matching.Regex.Match = 123println(s.mkString(" ")) //2 12 21 23println(k) //Some(123)println(k.get) //123} }11. 異常處理
捕捉異常的catch子句,語法與其他語言中不太一樣。在Scala里,借用了模式匹配的思想來做異常的匹配,因此,在catch的代碼里,是一系列case字句,如下例所示:
object Test {def main(args: Array[String]) {try {val f = new FileReader("input.txt")} catch {case ex: FileNotFoundException =>{println("Missing file exception")}case ex: IOException => {println("IO Exception")}}} }異常的其他特征跟Java差不多,這里就不在介紹。
12. 提取器
apply方法我們已經非常熟悉了,它幫助我們無需new操作就可以創建對象,而unapply方法則用于析構出對象,在模式匹配中特別提到,如果一個類要能夠應用于模式匹配當中,必須將類聲明為case class,因為一旦被定義為case class,scala會自動幫我們生成相應的方法,這些方法中就包括apply方法及unapply方法。
object EMail{//apply方法用于無new構造對象def apply(user: String, domain: String) = user + "@" + domain//unapply方法用于在模式匹配中充當extractordef unapply(str: String): Option[(String, String)] = {val parts = str split "@"if (parts.length == 2) Some(parts(0), parts(1)) else None} } object ApplyAndUnapply {val email=EMail("134214214","qq.com")def patternMatching(x:String)=x match {//下面的匹配會導致調用EMail.unapply(email)case EMail(user,domain) => println("user="+user+" domain="+domain)//匹配非法郵箱case _ => println("non illegal email")} }13. Scala的文件I/O
從屏幕上讀取用戶輸入:
import scala.io._ object Test {def main(args: Array[String]) {print("請輸入菜鳥教程官網 : " )val line = StdIn.readLine()println("謝謝,你輸入的是: " + line)} }從文件上讀寫內容:
import java.io._ import scala.io.Sourceobject Test {def main(args: Array[String]) {val writer = new PrintWriter(new File("test.txt" ))writer.write("寫內容")writer.close()Source.fromFile("test.txt" ).foreach{ print }} }14. 偏函數
Scala中的Partia Function是一個Trait,其的類型為PartialFunction[A,B],其中接收一個類型為A的參數,返回一個類型為B的結果。
scala> val pf:PartialFunction[Int,String] = { case 1=>"One" case 2=>"Two" case 3=>"Three" case _=>"Other" } pf: PartialFunction[Int,String] = <function1> scala> pf(1) res0: String = One scala> pf(2) res1: String = Two scala> pf(3) res2: String = Three scala> pf(4) res3: String = OtherisDefinedAt,這個函數的作用是判斷傳入來的參數是否在這個偏函數所處理的范圍內。
scala> pf.isDefinedAt(1) res4: Boolean = true scala> pf.isDefinedAt(2) res5: Boolean = true scala> pf.isDefinedAt("1") <console>:13: error: type mismatch; found : String("1") required: Int pf.isDefinedAt("1") ^ scala> pf.isDefinedAt(100) res7: Boolean = true總結
以上是生活随笔為你收集整理的scala学习 之 及 基本和高级用法(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: scala学习 之 环境搭建(一)
- 下一篇: Kafka学习 之 第一个例子(一)