日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Scala编程指南

發布時間:2023/12/4 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Scala编程指南 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.scala簡介

2004年,martin ordersky發明,javac的編譯器,后來spark,kafka應用廣泛,twitter應用推廣。它具備面向對象和函數式編程的特點。 官網:www.scala-lang.org,最近版本2.12.5,我們用的是2.10.4

2.環境安裝

1) windowsa) 安裝jdk-7u55-windows-x64.exeb) 安裝scala-2.10.4.msi安裝完以上兩步,不用做任何修改。測試:在控制臺下c:/>scalac) 安裝eclipse-java-juno-SR2-win32-x86_64.zip 解壓縮即可d) 安裝eclipse的scala插件update-site.zip解壓會有兩個目錄,features和plugins,分別把內容放到eclispe對應的目錄下。 e) 重啟eclipse提示"Upgrade of scala...",點yes提示框"setup Diagnostic",把Enable JDT weaving...選上根據提示重啟 2) linux

3.第一個程序

1) 交互式編程C:\Users\Administrator>scalaWelcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_5Type in expressions to have them evaluated.Type :help for more information.scala> 1+1res0: Int = 22) 腳本形式:通過創建文件來在eclipse/idea中執行代碼object Test {def main(args: Array[String] ) {println("Hello world")}}注1:上面這個是單例對象,這個里面只能存放靜態的東西注2:自動導入2個包java.lang._scala._注3:語句最后一行的分號不推薦寫

4.基礎語法

1) 變量和常量

val(常量)和var(變量) 盡可能的用val(1) 變量格式:var 變量名 [:數據類型] = 值例:var b :Int = 1var c = 2 //類型自動推斷(2) 常量格式:val 常量名 [:數據類型] = 值例:val b :Int = 1val b = 1b = 2 //報錯,常量不能修改(3) 常量可以用lazy修飾(了解)lazy val b :Int = 1 //b用到的時候再賦值

2) 數據類型

(1)數據類型序號 數據類型 說明1 Byte 8位有符號值,范圍從-128至1272 Short 16位有符號值,范圍從-32768至327673 Int 32位有符號值,范圍從-2147483648至21474836474 Long 64位有符號值,范圍從-9223372036854775808至92233720368547758075 Float 32位IEEE 754單精度浮點值6 Double 64位IEEE 754雙精度浮點值7 Char 16位無符號Unicode字符。范圍從U+0000到U+FFFF8 String 一個Char類型序列9 Boolean 文字值true或文字值false10 Unit 對應于無值,等價于void類型,只有一個對象叫()11 Null 只有一個對象叫null12 Nothing 在Scala中處于最底層,比如創建數組時不指定類型,就是Noting。抽象概念13 Any 任何類型的超類型; 任何對象的類型為Any14 AnyRef 任何引用類型的超類型(2)層次結構Scala.Any-AnyVal(值)-Int,Double等,Unit。-AnyRef(引用)-List,Set,Map,Seq,Iterable-java.lang.String-Null(3)重點類型:元組格式:(元素1, 元素2, ....)訪問:變量._N 其中N是元組元素的索引,從1開始例:var t = ("a", false, 1) //t的類型是scala.Tuple3var value = t._1 //"a"var m,n,(x,y,z) = ("a", false, 1) m :("a", false, 1) n :("a", false, 1)x : 'a'y : false:z : 1(4)重點類型:字符串i) 用的是java.lang.String,但是有時候根據需要,會隱式轉換到其它類型,比如調用reverse/sorted/sortWith/drop/slice等方法,這些方法定義在IndexedSeqOptimized中ii)多行字符串表示,開始和結束用(4)重點類型:字符串i)用的是java.lang.String,但是有時候根據需要,會隱式轉換到其它類型,比如調用reverse/sorted/sortWith/drop/slice等方法,這些方法定義在IndexedSeqOptimized中ii)多行字符串表示,開始和結束用(5)了解:符號類型符號字面量: '標識符,是scala.Symbol的實例,像模式匹配,類型判斷會比較常用。var flag = 'startif (flag == 'start) println(1) else println(2)

3) 運算符:scala沒有運算符,它運算符全部封裝成了方法。

算術:+ - * / %比較: == != > < >= <= 邏輯:&& || !賦值:= += -= *= /* %=位:& | ~ ^ >> << >>> #*/注:上面都是方法。例 1+2相當于1.+(2),其中+是方法,2是參數

4) 控制語句

(1) if,if...else...,if...else if...else...(2) scala中的if可以作為表達式用var x = if("hello"=="hell") 1 else 0(3) switch被模式匹配替換

5) 循環語句

(1)while,do..while和for都有,while和do..while很像,但是for差別很大。(2)for循環格式不同for(變量 <- 集合 if 條件判斷1;if 條件判斷2...) {所有條件判斷都滿足才執行}(3)沒有break和continue,用兩種方法可以代替i) 用for循環的條件判斷ii)方法2:非寫break,要做以下兩步//1) 引入一個包scala.util.control.Breaks._//2) 代碼塊用breakable修飾breakbreakable {for(i<-0 to 10) {println(i)if (i == 5) {break;}}}//0 1 2 3 4 5continuefor(i<-0 to 10) {breakable {if (i == 3 || i==6) {break;}println(i)}}//0 1 2 4 5 7 8 9 10(5) 集合框架(Array,List,Set,Map)在scala中,數組Array歸到集合的范疇包scala.collection,下面有兩個分支immutable(不可改變的,默認)和mutable(可變的)(1) 層次結構Traversable-Iterable(immutable不可改變的長度,默認)-Set 無序的集合,沒有重復元素HashSet,TreeSt 其中HashSet內部定義了別名Set-Map 鍵值對,映射HashMap,TreeMap 其中HashMap內部定義了別名Map-Seq 序列。有先后順序的元素集合-IndexedSeqArray:有索引的元素序列,因此可以通過下標訪問Vector,String,Range-LinearSeqList:線性的元素序列。訪問第1個元素,head方法,最后1個tail方法Queue,Stack(mutable可變的長度)-SetHashSet 其中HashSet內部定義了別名Set-MapHashMap 其中HashMap內部定義了別名Map-Seq-IndexedSeqArraySeq,StringBuilder-BufferArrayBuffer,ListBuffer-LinearSeqLinkedList,QueueStack重點記憶幾個不可變 可變Array ArrayBufferList ListBufferMap MapSet Set(2) 數組(非常重要):數據類型相同的元素,按照一定順序排序的集合。不可變數組 scala.Array可變長數組 scala.collection.mutable.ArrayBufferArray和ArrayBuffer1.Array創建var 變量名 = new Array[類型](長度) //var arr = new Array[Int](10)var 變量名 = Array(元素1,元素2,...) //var arr = Array(1,3,5,7),實際上是調用Array的方法apply取值:變量名(下標)2.ArrayBuffer創建var 變量名 = new ArrayBuffer[類型]() //var arr = new ArrayBuffer[Int]()var 變量名 = ArrayBuffer(元素1,元素2,...) //var arr = ArrayBuffer(1,3,5,7)3.共同方法sum 求和max 最大值min 最小值mkString(分隔符) 例:Array(1,3,5,7).mkString("|") //結果是1|3|5|7|9sorted 排序(從小到大)sortBysortWith 自定義排序reverse 翻轉toArray ArrayBuffer轉成ArraytoBuffer Array轉成ArrayBuffertoMap:如果Array內部元素是對偶元組,可以轉成maptoList:轉成list4.ArrayBuffer的獨有方法+= 追加元素++= 追加集合trimEnd(n):刪除末尾n個元素insert(index,value1,value2,..valueN):第index的位置,插入value1,value2,...valueN)remove(index,n):第index個位置刪除n個元素clear():清空5.遍歷i) 通過下標for (i <- 0 to 數組.length-1) {println(i)) //i表示數組的下標}ii)直接取值for (e <- 數組) {println(e)}6.使用yield創建新數組var arr = for (i <- 數組) yield i * 27.多維數組var arr = Array(Array(元素1...),Array(元素,...)..)遍歷for (i <- arr) {for (j <- i) {println(j)}} (3) List(不可變)/ListBuffer(可變):List 和java.util.List不同,一旦創建不可以改變。一般做數據分析用List1.List定義//創建var list1 = List("aa","bb","ccc") //調用apply方法var list2 = List.apply("aa","bb","ccc"))//右操作符:當方法名以:結尾時,為右操作符,先做右邊//::右操作符,拼接元素,var list3 = "aa"::"bb"::"cc"::Nil //Nil是空集合,先做"cc"::Nil,其中::是Nil的方法var list4 = list1:::"dd"::Nil //:::拼接集合2.常用方法//查head() 第一個元素take(n) 取前n個元素tail() 除了第1個的全部元素init() 除了最后一個的全部元素//增:+和+: 前者是尾部追加元素,后者是在頭部追加元素,和::很像+=或append 追加元素(ListBuffer)++= 追加數組/列表(ListBuffer):: 追加元素(List)::: 追加數組/列表(List)//刪drop(n) 丟棄前n個元素//改 updated(index,value):用value地替換第index的位置的元素//其他isEmpty是否為空reverse 翻轉splitAt(m):把列表前m個做成一組,后面是一組flatten:以參數的列表作為參數,把所有的元素連接到一起//toArray 轉成ArraytoArray 轉成Arrayzip:兩個List內部的元素合并,返回結果是List,元素是對偶元組grouped(n):每n個元素分成1組,返回是迭代器Iterator,可以再用toList轉成list類型3.ListBufferimport scala.collection.mutable.ListBuffervar list5 = ListBuffer("111","222","333")(4) Set:不存在重復元素的集合如果用可變的,需要引入import scala.collection.mutable.Set//定義var s = Set(3.0, 1.0)//追加元素s += 2.0 //s = s + 2.0s += 2.0 //元素重復,加不進去(5) Map//定義var m1 = Map(("zhang3",20),("li4",23),("wang5",21)) //使用元組var m2 = Map(("zhang3"->20),("li4"->23),("wang5"->21))var m3 = Map[String,Int]() //定義空map,得用可變的才有意義。//添加和更新 var m = scala.collection.mutable.Map(("zhang3", 20), ("li4", 23), ("wang5", 21))m += (("zhao6", 22)) //m = m.updated("zheng7",19) //和上面方法一樣m.put("wu", 22) m ++= Map(("a" -> 1), ("b" -> 2))//刪除m -= (("zhao6", 22))m.clear() 清空//查詢m(key):通過key獲取valuem.get(key) :通過key獲取value,返回類型Optionm.getOrElse(key,獲取不到設置的值)//其它size:元素個數contains(key):是否包含key,返回布爾類型keys 返回迭代器keySet 返回所有的key組成的Set集合values 返回迭代器,所有value組成的集合mapValues(函數)foreach(函數)//遍歷(6) Array和List都是不可變元素,有什么區別?

5.函數

Scala中函數和方法,在類中定義的函數就是方法。

1) 函數聲明

def 函數名([參數列表]):[返回類型] = {函數體return [表達式]}注1:如果函數沒有返回值,可以返回Unit,也可以不寫注2:方法的返回類型可以不寫,系統自動推導,但是遞歸必須寫。注3:函數體的大括號只有一行,可以不寫例:def add(a:Int,b:Int):Int = {var sum : Int = 0sum = a + breturn sum}

2) 函數調用

格式:方法之間調用:函數名([實參列表]) 例:add(3,5)對象之間調用:實例名.函數名([實參列表]) 例:s.add(3,5)

3) 值函數

(1)定義var 變量名:[輸入類型=>輸出類型] = {(參數列表)=>{函數體}}其中=>是函數映射符在參數列表后不能寫返回值類型最后一句不能寫returnLambda表達式(匿名函數,函數字面量):形如(參數列表)=>{函數體}就叫Lambda表達式

4) 高階函數

1) 定義:本身是函數,參數也是函數或返回值是函數例1:def m(f:(Double)=>Double):Double = {f(100)}def sqrt(x:Double)=Math.sqrt(x)調用m(sqrt) 結果是10.02) 常見高階函數集合中常見的高階函數(1)map def map[B, That](f: A => B): That 把函數應用于集合中的每一個元素,把返回由返回值組成的一個集合。例:Array("spark","hive","haddop").map((x:String)=>x.length)Array("spark","hive","haddop").map(x=>x.length)Array("spark","hive","haddop").map(_.length) // _占位符,代表一個元素Array("spark","hive","haddop").map(x=>println(x))Array("spark","hive","haddop").map(println _)Array("spark","hive","haddop").map(println) //如果只有一個參數,可以不寫(2) flatMap把函數應用于集合中的每一個元素,先做map,得到的結果flatten,生成新的集合。例:var list = List("a,b,c","d,e,f")var list2 = list.map(x=>x.split(",").toList) //List(List(a, b, c), List(d, e, f))list2.flatten //List(a,b,c,d,e,f)上面兩步可以寫成一步,相當于map+flatternlist.flatMap(x=>x.split(",").toList) //簡寫:list.flatMap(_.split(",").toList)問:map和flatMap有什么區別?(3)filter參數的函數表示對集合的每個元素過濾,參數函數結果是boolean,最后的返回值還是ListList(1,2,3,4).filter(x=>x>2) //List(3,4)Array(1,2,3,4,5,6,7,8).filter(x=>x%2==0) //取偶數 2,4,6,8Range(1,100).filter(_%2==0) //1到100的偶數Array(1,2,3,4,5,6,7,8).filter(x=>x%2==0).map(_*10)//20,40,60,80注:filterNot和filter相反(4)reduce/reduceLeft/reduceRight返回1個值。參數函數要求是二元運算符,作用于集合上,每次返回的結果作為新的輸入。Array(1,3,5,7).reduce((x,y)=>{println(x + ":" +y);x+y})Array(1,3,5,7).reduce(_+_) //第1個_代表第1個參數,第2個_代表第2個參數Array(1,3,5,7).reduceLeft((x,y)=>{println(x + ":" +y);x+y})Array(1,3,5,7).reduceRight((x,y)=>{println(x + ":" +y);x+y})注:reduce沒有特別的順序,reduceLeft從左到右計算,reduceRigth從右到左計算(5)fold/foldLeft/foldRight和reduce很像,只是增加了一個初始值,但是做并行時要注意。Array(1,3,5,7).fold(4)(_+_) //20List(2.0,3.0).fold(4.0)(Math.pow) //4096.0(6) par把計算轉換為并行化,把reduce拆分多個任務Array(1,3,5,7,8).par.fold(4)(_+_)Range(1,10).par.map(println)(7) groupBy 對列表進行分組,返回結果是mapvar data = List(("zhang3","male"),("li4","female"),("wang5","male"))data.groupBy(x=>x._2) //Map(male-> List((zhang3,male), (wang5,male)), female -> List((li4,female)))多介紹一個grouped(n):每n個分成一組例:List(1,3,5,7,9).grouped(2).toList //List(List(1, 3), List(5, 7), List(9))(8)partition把列表分成兩部分,第一個為滿足條件的,第二部為不滿足條件的List(1,3,5,7,9).partition(x=>x>4) //分成兩組:(List(5, 7, 9),List(1, 3))(9)diff差集,union并集并保留重復,intersect交集var n1 = List(1,2,3)var n2 = List(2,3,4)var n3 = n1.diff(n2) //也可以寫n1 diff n2 ,結果:List(1)var n4 = n2.diff(n1) //List(4)var n5 = n1 union n2 //List(1 2 3 2 3 4)var n6 = n1 intersect n2 //List(2,3)(10)distinct去掉重復元素List(1,2,3,2,3,4).distinct // List(1, 2, 3, 4)(11)mapValues(函數)還是map功能,只是處理的值是value,最終結果是mapMap(("zhang3",20),("li4",23),("wang5",21)).mapValues(_*2)//結果Map(zhang3 -> 40,li4 -> 46,wang5 -> 42)(12)foreach(函數)和map一樣,區別是它沒有返回值,通常用在遍歷(13)sorted 排序和sortBy和sortWithsorted 排序,最簡單,從小到大List(2,1,3,5,6,4).sorted //1 2 3 4 5 6sortBy:按照第幾列排List(("a",3),("b",1),("c",2)).sortBy(_._2) //按照第2列排sortWith:自定義排序List(2,1,3,5,6,4).sortWith((x,y)=>x>y) //從大到小3)下劃線_的用法(1) 讓匿名函數更簡潔,可以用下劃線_當做一個占位符。(2) java中導入包下的所有類用*,在scala中用_例:Java: import java.util.*scala: import java.util._(3) 下劃線_可以作為部分應用函數4) 函數柯里化柯里化(curring) 把接收多個參數的函數編程接收一個單一參數例1:不是柯里化,但是和柯里化很像def foo(factor : Int) = (x:Double)=>factor * x;調用:var f = foo(10)f(50)也可以直接寫:foo(10)(50)例2:柯里化def foo(factor : Int)(x:Double) = factor * x調用:foo(10)(50)注:柯里化函數不是高階函數,不能這么調用var f = foo(10)5)部分應用函數(Partial Applied Function)部分應用函數, 是指一個函數有N個參數, 而我們為其提供少于N個參數, 那就得到了一個部分應用函數.,柯里化函數和普通函數都有部分應用函數6)偏函數(Partial Function)(1)簡介引子:scala> List(1,2,3) map {case i:Int=>i+1}scala> List(1,2,3) map {(i:Int)=>i+1}上面兩個結果是一樣的。偏函數:上面例子中map后面的被包在花括號內的代碼,也就是沒有 match的一組case語句,就叫偏函數。偏函數類型是:PartialFunction[A,B],A的參數類型,B是返回結果類型。平常我們都是直接用。例1:val foo : PartialFunction[Int,String] = { //類型PartialFunction[Int,String]可以省略case y if y % 2 == 0 => y + " 是偶數"}println(foo(10)) //10 is Evenprintln(foo(11)) //拋出錯誤: scala.MatchError----反編譯:相當于foo是一個對象,調用對象的 apply方法private final PartialFunction foo = new PartialFunction{public final Object apply(int i){Object obj;if (i % 2 == 0)obj = y + " 是偶數"elseobj = i;return obj;}}foo.apply(10) (2)orElse:可以把多個偏函數結合起來,效果類似case語句。val or1 = {case 1 => "One"}val or2 = {case 2 => "Two"}val or_ = {case _ => "Other"}val or = or1 orElse or2 orElse or_ //使用orElse將多個偏結合起來//測試:scala> or(1) // one scala> or(20) //other(3) andThen: 相當于方法的連續調用,比如g(f(x))。 val a = {case cs if cs == 1 => "One"}val b = {case cs if cs eq "One" => "The num is 1"}val c = a andThen b//測試num(1) //The num is 1(4) 普通函數的偏應用函數定義比如我先定義一個函數:def sum(a:Int,b:Int,c:Int) = a + b + c;那么就可以從這個函數衍生出一個偏應用函數是這樣的:def foo = sum(1, _:Int, _:Int) 調用foo(2,3), 相當于調用sum(1,2,3) 兩個_分別對應函數sum對應位置的參數. 用處:當你在代碼中需要多次調用一個函數, 而其中的某個參數又總是一樣的時候, 使用這個可以少敲一些代碼(5)柯里化函數中的偏應用函數定義def sum(a:Int)(b:Int)(c:Int) = a + b + c; // (a: Int)(b: Int)(c: Int)Intval result = sum _ //柯里化賦值,結果是部分應用函數 Int => (Int => (Int => Int)) = <function1>sum(1)(2)(3) //6result(1)(2)(3) //6result(1)(_: Int)(3) //部分應用函數:Int => Int = <function1>2018/4/5

6.面向對象

1) 類和對象

(1) 簡介scala中的類和java中的類一樣,都是通過class定義class Person { //不寫public,默認public//var name:String; //報錯,變量必須要被初始化,而java不需要被初始化,系統會自動賦初值var name :String = null //正確var age :Int = _ //正確,不知道賦上面值時,用_占位符}(2)創建對象var p1 = new Person()var p2 = new Person //沒有參數,可以省略()(3) 類成員訪問p1.name = "zhang3" //設置,底層調用的是p1.name_=("zhang3"),其中_=是方法println(p1.name) //取值非要用getter和setter,屬性前加入 @BeanProperty(導入包:scala.beans._)(4) 單例對象scala中不支持靜態成員的語法,通過單例對象實現object Test {private var id:Int = 0def m() ={id += 1id}}測試:scala>Test.m //1scala>Test.m //2(5) 伴生對象和伴生類單例對象和類如果同名的話,單例對象也叫伴生對象。例:class A {}object A {}伴生對象和伴生類可以互相訪問,即使是private也可以訪問,但是private[this]不能訪問一個文件可以有多個類(6) apply方法object Dog {def apply():Unit = {println(1)}def apply(name:String):Unit = {println(2)}def main(args: Array[String]) { var d1 = Dog() //調用Apply()方法var d2 = Dog("hello") //調用Apply(String)方法}}

2) 主構造方法

(1)定義每個類都有主構造方法,參數放在類名后,構造方法和類交織在一起。class Student(var name:String, var age:Int) 反編譯代碼:public class Student {private String name;private int age;public Student(String name, int age) {println("hello:" + name)this.name = name;this.age = age;}//getter和setter//name()和name_$eq(String)//age()和age_$eq(int)@Overridepublic String toString() {return name + ":" + age}} Student s = new Student();System.out.println(s) //打印s,就是打印s.toString()例:class Student(var name:String, var age:Int) {println("hello") //加在主構造方法中override def toString = name + ":" +age}var s = new Student()println(s)(2) 帶有默認參數的主構造方法構造方法可以帶有默認參數。class Student(var name:String, var age:Int, val gender:String="female") {println("執行主構造方法")}var s1 = new Student("zhang3", 18, "male") //正確var s2 = new Student("li4", 18) //正確s2.name = "wang5"s2.gender = "male"(3) 私有構造方法class Student private(var name:String, var age:Int)var s = new Student("li4", 18)//報錯

3) 輔助構造方法

(1) 非主構造方法,方法名用this(2) 非主構造方法,也可以有默認值class Dog(val id:String) {var name :String = "大黃"def this(id:String,name:String) {this(id) this.name = name}override def toString = name + ":" + id}//測試var d1 = new Dog("1111")var d2 = new Dog("2222","二黃")println(d1)println(d2)

4) 繼承和多態

(1) 繼承用extendsclass Person(var name:String, var age:Int)//沒有寫var,表示繼承父類的屬性class Student(name:String,age:Int, var no:String) extends Person(name,age)//測試new Person("tom", 18)new Student("jack",19,"123")Student從父類繼承name和age,所以前面不要加變量var或者val,no是新加的元素,所以需要var(2) 多態多種形態,動態綁定,在執行期間確定引用對象的實際類型,根據其實際類型調用相應的方法,也就是子類可以賦值給父類?!? class Human(var name:String, var age:Int) {def walk():Unit = {println("walk in Human")} }class Teacher(name:String,age:Int) extends Human(name,age) {override def walk():Unit = {println("walk in Teacher")} }class Doctor(name:String,age:Int) extends Human(name,age) {override def walk():Unit = {println("walk in Doctor")} }//測試var x:Human = new Teacher("tom", 18)var y:Human = new Doctor("jack", 19)x.walk //walk in Teachery.walk //walk in Doctor

5) 成員訪問控制

private 類內+伴生對象protected 同包+子類不寫:默認是public,都可以訪問特別之處(1) private[this] 只能類內訪問class Person {private[this] var name:String = "zhang3" //只能類內private var age: Int = 18 //類內+伴生對象}object Person {def main(args:Array[String]) {var p = new Personprint(p.age) //18//print(p.name) //報錯}}(2) 主構造方法也可以加入成員訪問控制class Person(private var name:String, protected var age:Int)

6) 抽象類

不能能被實例化的類??梢杂谐橄蠓椒?#xff0c;非抽象方法,成員變量。但是scala增加了抽象成員變量。abstract class Person {var name:String //抽象成員變量def walk //抽象方法}//子類如果繼承,必須要實現抽象變量和抽象方法,如果不想實現,子類也需要是抽象類class Student extends Person {override var name:String = _ //覆蓋父類的抽象變量override def walk():Unit = {println("walk in Student")} //覆蓋父親的抽象方法}

7) 內部類和內部對象

定義在對象或者類內部的類object Ex extends App {class Student(var name:String, var age:Int) { //內部類class Grade(var name:String)//內部對象object Utils {def print(name:String) = println(name)}}object Student {//內部類class Printer {def print(name:String) = println(name)}}var s = new Student("tom", 18)//var grade = new Student.Grade("xxx") //此處出錯,怎么糾正?s.Utils.print("student:util.print(String)")new Student.Printer().print("Student.Printer().print(String)")}

8) 匿名類

沒有名字的類,一般用在某個類只在代碼出現一次abstract class Person(var name:String, var age:Int) {def print():Unit}//調用//var p = new Person("tom", 18) //錯誤,抽象類不能new,也就是不能創建實例var p = new Person("tom", 18) {def print():Unit = println("hello")}p.print();

9) trait(特質),其實就是接口,相當于jdk1.8的接口,比jdk1.8以下版本的接口多了非抽象的變量和方法

(1) scala沒有提供接口interface,而用trait關鍵字,其實和接口等價。使用方法:extends或with,第一個實現的特質用extends,之后的用with它和抽象基本一樣,可有抽象成員,抽象方法,具體成員和具體方法例:trait Closeable {def close():Unit}trait Clonable {def open():Unit}//第一個接口用extends,后面的用withclass File(var name:String) extends Closeable with Clonable{def close():Unit = println("file close")def open():Unit = println("file open")}//寫一個全的traittrait Book {var a : Long = _ //具體成員var b : Long //抽象成員def add(x:Int) //抽象方法def add2(x:Int):Int = x+2 //具體方法}var b = new Book(){ //定義匿名內部類,只需要實現抽象方法和抽象成員變量即可override var b : Long = 1def add(x:Int) = println(x)}b.add(6)println(b.add2(5))

10) 自身類型(self type)

trait A {val a = 1}trait B {this:A=> //引入接口A,相當于把A的東西全放進來var b = 2def xx() {println(this.a + ":" + this.b)}}class C extends B with A//調用new C().xx()//還有一種特殊用法,this定義別名class D {self=> //為this定義別名self,也可以是其他名字var x = 2def foo = self.x + this.x}//常見用法,用在內部類引用外部類的變量class OuterClass {xx=> //為this定義別名var value = "here"class InnerClass {println(xx.value)}}

7.包

1) 包定義

(1) 第一種定義方式,和java很像,package cn.cda.day1(2) 第二種定義方式package cn{package cda {package day1 {class Teacher {}}package day2 {class Student}}}以上方式不推薦

2) 作用域

scala中有private,proteced和默認(public)外,還有private[x]和protected[x],其中x可以是包/類/單例對象

3) 包對象

通過package關鍵字聲明的對象為保對象,主要用于對常量和工具函數的封裝,通過包名引用。package object Math {val PI = 3.14}class Test {def main(args:Array[String]) {m(3) //3.14*9=28.62}def m(r:Double) = Math.PI * r * r}

4) import

導入包下的所有的類和對象,還可以引入重命名和類隱藏等功能。1) 隱式導入默認導入的包,通過下面命令查看scala>:import2) 引入重命名import java.util.{HashMap=>JavaHashMap}import scala.collection.immutable.HashMapvar map = new JavaHashMap3) 類隱藏引入java.util.下的所有類,但是不想要HashMapimport java.util.{HashMap=>_,_} //隱藏HashMapimport scala.collection.immutable.HashMapvar map = new HashMap

8 模式匹配

1) 簡介

模式匹配類似switch語言,簡單用法就是替代多層的if else語句和類型檢查和快速匹配。它使用了關鍵字match來替換switch,一旦匹配到了,后面不再執行,所以不用break語句。scala有一個十分強大的模式匹配機制,可以用到很多場合。如switch,類型檢查等,格式:case 變量: 類型=> 代碼例:java和scala進行比較 --javafor (int i = 1; i < 5 ; i++) {switch (i) {case 1:System.out.println(1);break;case 2:System.out.println(2);//不帶break會陷入其它分支,同時輸出2,3case 3:System.out.println(3);break;default:System.out.println("default");//case語句不能接表達式//case i%5==0:System.out.println("10")}}--scalafor (i <- 1 to 5) {i match {case 1 => println(1) //不需要寫break,case 2 => println(2)case 3 => println(3) case _ => println("default")}}//上面的case語句中,還可以加入表達式for (i <- 1 to 5) {i match {case 1 => println(1) //不需要寫break,case x if (x%2 == 0) => println(s"$x 是偶數") //加入表達式 ,此時的x是形參,i是實參 case _ => //這句話表示其它任何情況都不進行操作}}//還可以作為函數體def m(x:Int) = x match {case 5 => "整數5"case y if (y % 2 == 0) => "能被2整除" //注意y認為是形參case _ => "其它整數"}println(m(5)//反編譯:public String m(int x){switch (x){default: tmpTernaryOp = "其它整數"; break;}return x % 2 == 0 ? "能被2整除" : "整數5";"}

2) 模式匹配的7大類型

(1)常量模式case后面接的全部是常量例:for (i <- 1 to 5) {i match {case 1 => println(1) //不需要寫break,case 2 => println(2)case 3 => println(3) case _ => println("default")//可以寫成 case x}}(2)變量模式case后面接的是變量例:def m(i:Int) = i match {case x if (x % 2 == 0) => "能被2整除" //這個順序是有關系的case x if (x % 3 == 0) => "能被3整除" case x => "能被2或3意外的數" // 等價于 case _}//調用println(m(5))println(m(4))println(m(3)) (3)構造方法模式與創建對象相反,見下例1case class Dog(val name:String, val age:Int)def m(x:AnyRef) = x match {case Dog(name,age)=>println(name+":"+age)// 構造函數模式,與創建對象相反,對對象進行析構,調用unapply方法,普通類沒有,case類系統會生成。case _=>}//測試val dog = Dog("Pet", 2) //調用apply創建對象m(dog)例2:對部分變量析構case class Dog(val name:String, val age:Int)def m(x:AnyRef) = x match {case Dog(_,age)=>println(age) //表示匹配這個成員域,但是不需要使用nam的值case _=>}(4)序列模式用于匹配Seq集合的,用法和上面類似,但是可以使用_*來匹配多個元素,并且只能放在模式內的最后例:def m(x:AnyRef) = x match {case Array(a,b)=>println("1")case Array(a,_,b,_*)=>println("2") //_匹配第2個元素,_*匹配任意多,只能放模式最后case _=>}//調用 m(Array(1,2,3,4))(5)元組模式和上面用法相似,但是不能使用_*,_*只能在序列模式中使用。例:def m(x:AnyRef) = x match {case (a,b)=>println("1")case (a,_,b,_)=>println("2")//case (a,_*)//元素模式不能使用_*case _=>}var t = (1,2,3,4)m(t)(6)類型模式匹配變量的類型class Aclass Bclass C extends Adef m(x:AnyRef) = x match {case y:String=>println(1)case y:B=>println(2)case y:A=>println(3)case _=>println(4)}//測試val b = new Bval c = new Cm("hello")m(b)m(c)反編譯源代碼 public void m(Object x){if ((x instanceof String)){this.println(1);}else if ((x instanceof B)){this.println(2);}else if ((x instanceof A)){this.println(3);}else {this.println(4);}}(7)變量綁定模式如果想要的不是析構對象,而且返回匹配模式的對象,很常用例1case class Dog(val name:String,val age:Int){override def toString=name+":"+age}def m(x:AnyRef) = x match { //Dog(_,_)用于匹配輸入對象中包括兩個成員變量的Dog對象,匹配成功后把對象賦值給dcase d@Dog(_,_) => println("變量綁定模式返回的變量值:" + d)case _=>}// 測試val dog = new Dog("Pet", 2)m(dog)反編譯源代碼:public void m(Object x) {if ((x instanceof Dog)){Dog d = (Dog)x;this.println("變量綁定模式返回的變量值:" + d)}else {}}例2:更常見,也更復雜val list = List(List(1,2,3,5),List(4,5,6,7,8,9))def m(x:AnyRef) = x match {//變量綁定模式case e1@List(_,e2@List(4,_*))=>println("e1:" + e1 + ",e2:" + e2)case _=>}//調用 m(list)//e1:List(List(1, 2, 3, 5), List(4, 5, 6, 7, 8, 9)),e2:List(4, 5, 6, 7, 8, 9)---反編譯代碼:public void m(Object x) { if ((x instanceof List)){List e1 = (List)x;Some localSome1 = List..MODULE$.unapplySeq(e1);if ((!localSome1.isEmpty()) && (localSome1.get() != null) && (((LinearSeqOptimized)localSome1.get()).lengthCompare(2) == 0)){Object e2 = ((LinearSeqOptimized)localSome1.get()).apply(1);if ((e2 instanceof List)){List localList2 = (List)e2;Some localSome2 = List..MODULE$.unapplySeq(localList2);if ((!localSome2.isEmpty()) && (localSome2.get() != null) && (((LinearSeqOptimized)localSome2.get()).lengthCompare(1) >= 0)){Object localObject2 = ((LinearSeqOptimized)localSome2.get()).apply(0);if (BoxesRunTime.equals(BoxesRunTime.boxToInteger(4), localObject2)){Predef..MODULE$.println(new StringBuilder().append("e1:").append(e1).append(",e2:").append(localList2).toString());localBoxedUnit = BoxedUnit.UNIT; return;}}}}}}

3) 正則表達式與模式匹配(略)

(1)Scala正則表達式 (2)正則表達式在模式匹配中的應用

4) for循環種的模式匹配

(1)變量模式匹配for((x,y)<-Map("a"->1,"b"->2,"c"->3)) {println(x + ":" + y)}(2) 常量模式匹配//下面只有"b"被匹配到,輸出2for(("b",y)<-Map("a"->1,"b"->2,"c"->3)) {println(y)}(3) 變量綁定模式匹配//可以綁定變量xxx和yyyfor((xxx@"b",yyy@y)<-Map("a"->1,"b"->2,"c"->3)) {println(xxx + ":" + yyy)}(4) 類型模式匹配//類型value為字符串才能匹配到for((x,y:String)<-Map("a"->1,"b"->"hello","c"->3)) {println(x + ":" + y)}(5) 構造方法模式匹配case class Dog(val name:String, val age:Int)case class Cat(val name:String, val age:Int)for (Dog(name,age) <- List(Dog("a",1),Cat("b",2),Dog("c",3))) {println(name + ":" + age)}上面輸出第1個和第3個for (List(first,_*) <- List(List(1,2,3), List(4,5,6,7))) {println(first)}(6) 序列模式匹配可以用_*

5) 樣例類和樣例對象

樣列類(case class):使用case修飾的類。就是增加了一些方法,比如unapply。用在上面的模式匹配. 1) 樣例類:是一種特殊的類,可以用于模式匹配。case class是多例,case object是單例。上面已經做了一個例子了,下面再做一個例子,用到了sealted.trait中前面加入 seatled,表示密封類a) 其修飾的trait,class只能在當前文件里面被繼承b) 并且用sealed修飾這樣做的目的是告訴scala編譯器在檢查模式匹配的時候,讓scala知道這些case的所有情況,scala就能夠在編譯的時候進行檢查,看你寫的代碼是否有沒有漏掉什么沒case到,減少編程的錯誤。例:sealed trait Acase class B(id:String,name:String) extends Acase class C(id:String) extends Acase class D(id:String) extends Adef m(x:A) = x match {case B(id,name)=>"1"case C(id)=>"2" // 這一行如果不寫,系統會警告,這樣的好處是提示你不要漏了case D(id)=>"3"} //測試val b = new B("1","zhang3")println(m(b))// 注意,如果注釋掉上面的B,C,D中的任何一句,系統會警告,所以在子類眾多的時候,要用 sealed修飾帶來的好處。2) 樣例對象(case object)上面看到每個子類都有自己的屬性,但是實際開發,可能不需要屬性,如果不定義屬性,編譯器會警告。這時候需要定義樣例對象(case object)來聲明sealed trait Acase class B(id:String,name:String) extends Acase class C(id:String) extends Acase class D(id:String) extends Acase object E extends Adef m(x:A) = x match {case B(id,name)=>"1"case C(id)=>"2" case D(id)=>"3"case E=>"4"} //測試val b = new B("1","zhang3")println(m(b))println(m(E)) //直接調用分析:a)case class會先創建對象,而case object可以直接使用b)case class會生成兩個字節碼文件,而case object是一個c)case class生成的伴生對象會自動實現 apply和unapply方法,而case object不會使用 case object可以提高速度,減少開銷 例2:spark中的一段代碼如下,看學生是否看懂?import scala.util.Randomcase class SubmitTask(id: String, name: String)case class HeartBeat(time: Long)case object CheckTimeOutTask //定義樣例對象object Test extends App {var arr = Array(CheckTimeOutTask, HeartBeat(2333), SubmitTask("0001", "task-001"));arr(Random.nextInt(arr.length)) match {case SubmitTask(id, name) => { println(s"$id,$name") }case HeartBeat(time) => { println(time) }case CheckTimeOutTask => { println("check") }}3) Option類型Option類型也是樣本類,表示值是可選的,要么無值,要么有值,Option的子類有Some和None用Some(x) 表示有值,x是真正的返回值用None表示無值val map = Map("cn"->1,"jp"->2) val v = map.get("cn") match { //get方法返回 Option類型case Some(i) => icase None => 0}查看map集合的源代碼: def get(key: A): Option[B]查看some的源代碼:case class Some[+A](x: A) extends Option[A] 查看None的源代碼:case object None extends Option[Nothing] {我們常用 getOrElse("c",0)

9 隱式轉換

1)隱式轉換簡介

scala提供的一種強大的語法特征,必須掌握。開發中,會自動轉換。scala定義了一些隱式轉換,會自動導入他們。比如 1 to 5 調用 1.to(5),但是to并不是Int類型的方法,它會自動轉換為 scala.runtime.RichInt源代碼:系統自動導入Predef對象,在scala.Predef中,objectPredef父類LowPriorityImplicits中方法intWrapper(x:Int)=new runtime.RichInt(x)不僅如此, Int還可以轉換為其它類型(AnyRef,Integer,Double,Float,Long),可以由其它類型轉換而來查看所有的隱式轉換scala>:implicit -vscala.Int的伴生對象包含了Int到其它類型的轉換implicit def int2long(x:Int) : Long = x.toLongimplicit def int2float(x:Int) : Float = x.toFloatPredef對象中也可以了大量的隱式轉換函數,如Scala數值類型到java數值類型的轉換implicit def byte2Byte(x:Byte) = java.lang.Byte.valueOf(x)正是這些隱式轉換函數的存在,簡化了Scala代碼。

2) 隱式轉換

(1)隱式轉換函數Scala默認提供了大量的隱式轉換,比如Int到Float,但是如果想實現Float到Int,需要自己定義例:val value : Int = 1.0f // 報錯修改:implicit def m(x:Float) = x.toInt //toInt方法有,但是沒有隱式轉換val value : Int = 1.0f原理:當編譯機發現類型不匹配,就會查找隱私轉換函數--------xjad反編譯----------- public int m(float x){return (int)x;}int value = m(1.0F);System.out.println(value); }注:名稱可以是任意(與參數類型和返回值有關),但不要重復,否則隱式轉換報錯,不過盡量給名字寫的有意義(2) 隱式類隱式類的轉換不像隱式轉換函數那么明顯。例;implicit class A (val name:String) { def bark = println(name + " is barking")}//調用"Nacy".bark //由于String沒有 bark方法,因此會找隱式類,由于A的主構造方法是String,就會調用。---源代碼 public static class Test$A{private final String name;public Test$A(String name) {this.name = name}public void bark(){System.out.println(name + " is barking");}} public final class Test${public void main(String args[]){new Test.A("Nacy").bark();//把“nacy”轉換為創建A的對象}}(3) 隱式對象單例對象前加入implicit關鍵字trait A[T] {def m(x:T):T }//隱式轉換對象:整數的平方implicit object AInt extends A[Int]{def m(x:Int) = x * x}//隱式轉換對象:字符串的乘積implicit object BString extends A[String] {def m(x:String) = x * 2}//定了一個函數:函數具有泛型參數def foo[T:A](x:T) = {val obj = implicitly[A[T]] //通過 implicitly方法,知道T的類型,創建A的相應子類對象obj.m(x)}//調用println(foo(5)) //25,從下面源代碼可以看到,翻譯成java時傳遞兩個參數println(foo("5"))//"55"------源代碼----public final class Test${public Object foo(Object x, Test.A o) { //傳遞A的子類對象Test.A obj = (Test.A)(o);return obj.m(x);}public void main(String args[]) {foo(5,傳遞Test.AInt的單例對象);}}public final class Test{interface A{Object m(Object obj);}}public static class AInt implements A{public int m(int x){ return x * x; }}public static class BString implements A{public String m(String x){ return x * 2}}(4) 隱式參數 上面的implicitly方法換一種形式,定義在參數中 , 參數前加了implicit,這種形式的參數成為隱式參數上面代碼可以化簡如下:def foo[T:A](x:T)(implicit obj:A[T]) = { //知道T的類型,創建A的相應子類對象obj.m(x)}//編譯后的源代碼基本不變(5) 隱式值隱式值也叫隱式變量,前面用implicit修飾例1:implicit val x : Double = 2.55def sqrt(implicit y: Double) = Math.sqrt(y)//測試 scala> sqrt //不指定參數,編譯器再當前作用于查找相應的隱式值或隱式對象,找到x傳給它--xjad反編譯public final class Test${private final double x = 2.5499999999999998D; public double sqrt(double y) {return Math.sqrt(y);}public void main(String args[]){sqrt(x);}}例2:改寫上面的代碼:trait A[T] {def m(x:T):T }class AInt extends A[Int]{ //普通類def m(x:Int) = x * x}class BString extends A[String] {def m(x:String) = x * 2}implicit val a = new AInt //隱式值,上面的例子是隱式對象implicit val b = new BStringdef foo[T:A](x:T)(implicit obj:A[T]) = { obj.m(x)}//調用println(foo(5)) //25println(foo("5"))//"55"

3) 隱式參數使用常見問題

1. 當函數沒有柯里化,implicit關鍵字組用于函數列表中的所有參數scala>def m(implicit x:Double,y:Double) = x * y //所有參數都作用implicitm: (implicit x: Double, implicit y: Double)Doublescala>implicit val d = 2.5scala>m //結果 6.252. 隱式函數使用時要么全部指定,要么全不指定,不能只指定部分如果上面調用scala>m(3.0) 就報錯scala>m(3.0,3.0)3. 同類型的隱式值只在當前作用域內出現1次如果再定義 scala>implicit val d2 = 3.5scala>m // 報錯 4. 在定義隱式函數時,implicit關鍵字只能在參數開頭//報錯,不能定義在第2個參數def m(x:Double,implicit y:Double) = x * y 5. 如果想達到函數def m(x:Double,implicit y:Double)只將參數y定義為隱式函數的目的,需要對函數柯里化//柯里化后,只有參數y是隱式參數def m(x:Double)(implicit y:Double) = x * yimplicit val d = 4.0m(3)6. 柯里化的函數implicit關鍵字只能作用于最后一個參數def m(x:Double)(y:Double)(implicit z:Double) = x * y * z //正確def m(implicit x:Double)(y:Double)(z:Double) = x * y * z //錯誤,沒有作用于最后一個 7. implicit關鍵字只在隱式參數中出現1次,對柯里化的函數也不例外def m(implicit x:Double,implicit y:Double) = x * y // 錯誤8. 匿名函數不能使用隱式參數val m = (x:Double, y:Double)=>x * y // 正確val m = (implicit x:Double, y:Double)=>x * y9. 柯里化的函數如果有隱式參數,則不能使用其偏應用函數def m(x:Double)(y:Double) = x * yval t1 = m _ //賦值給t1, 定義兩個參數的偏函數t1(3,0)(4,0)val t2 = m(3.0) _t2(4.0)以上都沒有問題,但是如果下面有隱式參數,則會報錯 def m(x:Double)(implicit y:Double) = x * yval p = m _ //報錯

4)隱式轉換規則與問題

(1) 隱式轉換的若干規則a) 作用域規則必須在當前作用域才能起作用。c) 無歧義規則不能存在兩個一樣功能的隱式轉換函數。d) 一次轉換原則只經過1次隱式轉換,不能經過多次(2) 是否調用隱式轉換非必要的情況下,盡量少用,如果是為了炫耀,大膽使用。

10 類型參數

1) 簡介

(1) 簡介在類的聲明中,定義一些泛型,然后在類內部,就可以使用這些泛型類型。scala泛型和java泛型基本相同,只是Java語法格式為<>,而Scala語法給是為[]//比如: java中List<T> ,而Scala中為 List[T]//比如:trait Map[A,B] extends Iterable[(A,B)] with GenMap[A,B] with scala.collection.Map[A,B] {override def empty:Map[A,B] = Map.empty} (2) 泛型類class Person[T](var name :T)class Student[T,S](name:T, var age:S) extends Person(name)//name前不寫var表示繼承例:新生入學,填寫id時候,有的人用整數,有的人用字符串class Student[T](val id:T) {def get(hukouId:T) = id + ":" + hukouId}val a = new Student[Int](111)a.get(4)val a = new Student(111) //不寫Int,可以自動推斷val a = new Student[String]("111")//測試class Student[A,B](var name:String, var age:Int)println(new Student[String,Int]("a",1).name)(3) 泛型方法與泛型類類似,給某個函數在聲明時指定泛型類型def getCard[T](content: T) = {if (content.isInstanceOf[Int]) 1 //等價于java的instanceOfelse if (content.isInstanceOf[String]) 2else 3}//測試getCard(111) //1getCard("222") //2getCard(false) //3(4) 類型通配符在java中,采用List<?>來做,但是scala中,沒有采用上面的特性,是通過存在類型來解決類[T,U,..] forSome {type T;type U;...}例://存在類型Array[T] forSome {type T}def printAll(x : Array[T] forSome {type T}) = {for (i <- x) {println(i)}}---源代碼:public void printAll(Object x) {Predef$.MODULE$.genericArrayOps(x).foreach(new Serializable() {public final void apply(Object i) {System.out.println(i);}});}//可以寫簡化形式def printAll(x : Array[_]) = {for (i <- x) {prntln(i)}}

2) 類型變量界定

對泛型范圍進行界定,而不是任意類型。比如必須是某個類的子類,或者是父類,才能正常使用。java中,這么定義://List<? extends Object> 接收object的子類,包括Object//List<? super Integer> 接收Integer的父類,包括Integerscala沒有采用,它采用對應<:>:例1:class Person(val name: String) {def makeFriends(other: Person) = println(this.name + "和" + other.name + "交朋友")}class Student(name: String) extends Person(name)class Party[T <: Person](p1: T, p2: T) {def play = p1.makeFriends(p2)}//調用var p1 = new Student("zhang3")var p2 = new Student("li4")new Party[Student](p1, p2).play例2: def compare[T <:Comparable[T]](first:T,second:T) = {//表示Comparable的子類if (first.compareTo(second)>0) firstelsesecond}調用;:compare("A,"B”) //B

3) 視圖界定

用<%表示: 相當于上面的<:加上隱式轉化class Person(val name: String) {def makeFriends(other: Person) = println(this.name + "和" + other.name + "交朋友")}class Teacher(var name: String)class Party[T <% Person](p1: T, p2: T) {def play = p1.makeFriends(p2)}implicit def teacher2Person(t: Teacher) : Person = new Person(t.name)//調用var p1 = new Teacher("zhang3")var p2 = new Teacher("li4")new Party[Teacher](p1, p2).play

4) 上下文界定

回顧以前:>: 繼承:要求是長輩<: 繼承:要求是低輩<% 繼承+隱式轉換 這次T:A T是一個泛型, A是個類,要求調用這個類的函數時,必須要隱式引入A[T]。舉個例子:T是整數Int,A是Ordering(理解成排序comparator,系統有這個類),要求使用時候要引入隱式值Ordering[Int]class Test[T:Ordering](val a:T,val b:T) {def bigger(implicit myComparator:Ordering[T]) {if (myComparator.compare(a,b)>0)println(a +":"+ myComparator.getClass)elseprintln(b)}}new Test(1,2).bigger //2----反編譯----public class Test{private final Object a;private final Object b;public Test(Object a, Object b,){this.a = a;this.b = b; }public void bigger(Ordering myComparator){if (myComparator.compare(a(), b()) > 0)System.out.println(a());elseSystem.out..println(b());}}new Test(1,2).bigger(系統自帶的實現Int的Ordering對象)

5) 多重界定

(1) T:A:B 隱式引入A[T],B[T](2) T<%A<%B 存在T到A,T到B的隱式轉換(3) T1>:T<:T2 T1是T類型的超類,T2也是T類型的超類class A[T]class B[T]implicit val a = new A[String]implicit val b = new B[String]//1.當前作用域中,必須存在兩個隱式值,類型為 A[T],B[T]def test[T:A:B](x:T) = println(x) test("測試1")implicit def t2A[T](x:T) = new A[T]implicit def t2B[T](x:T) = new B[T]//2.當前作用域中,必須存在T到A,T到B的隱式轉換def test2[T <% A[T] <% B[T]](x:T) = println(x)test2("測試2")

6) 協變與逆變

//解決問題,如果Child是Father的子類,那么List<Child>是不是List<Father>的子類,答案:不是,但這會造成很多問題。但Scala只要靈活運用協變與逆變,就可以解決這個問題協變 +T 當A是B的子類, 那么func(A) 是func(B)的子類例:class Fatherclass Child extends Fatherclass Test[+T]var x = new Test[Father]var y = new Test[Child]//此事,x也是y的父親x = y //正確y = x //錯誤逆變 -T當A是B的子類, 那么func(A) 是func(B)的父類

===========================================================================
11 scala并發編程基礎(講義已經單獨做成doc文檔:講義-Actor編程.docx)
1) 簡介
(1) 并發和并行
并發:在一臺處理器上“同時”處理多個任務,一個時刻只有一個任務跑
并行:在多臺處理器上同時處理多個任務,一個時刻有有個任務跑。

優化:并發:增加進程或者線程,縱向擴展并行:增加cpu,橫向擴展Actor模型:可以同時解決縱向和橫向擴展

總結

以上是生活随笔為你收集整理的Scala编程指南的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。