標籤:

Scala 包、類、特質和泛型

Scala的代碼採用了Java平台完整的包機制,並且更加靈活和易於擴展。

有兩種方式命名包,一種是和Java一樣吧package子句放在文件頂端。

package com.stanley.scalan

另一種把代碼放進包里的方式類似C#的命名空間。可以在package 子句之後把要放到包里的定義,用花括弧括起來。除此之外,可以把文件的不同部分放在不同的包里。例如,類的業務代碼和測試代碼可以放在同一個文件的不同包里。

package com.neusoft.effective {npackage scala {nclass Biz {n }n }nnpackage test {nclass TestBiz {nval biz = new scala.Bizn }n }n}n

包和成員的引用與Java相同,import關鍵字。不同的是,引用包中所有是的通配符是"_",並且同一個包引用多個類是,不需要另起一行。

import org.scalactic.ErrorMessagenimport org.scalautils._nimport org.scalatest.{PathEngine,Payloads}n

更加靈活的是,scala的import可以出現在任何地方。

在函數里

def calc(x: Int) = {nimport Int._n//Int.MaxValuen println(MaxValue)nprintln(MinValue)nnimport x._n//x.toStringn toStringn}n

在類體里

class Calc{nimport Int._nval max = MaxValuen}n

引用Numeric並重命名為Number

import scala.math.{Numeric=>Number}n

另一種重命名方式

type XX = java.lang.Integernval x = new XX(1)n

只引用math包中Numeric,其它所有成員除外。

import scala.math.{Numeric=>Numeric,_}n

引用math包中所有成員,除Numeric外。

import scala.math.{Numeric=>_,_}n

部分引用

import org._nval x:scalactic.ErrorMessagen

在編程意義上,類可以被認為是在運行期,能被實例化成許多對象的靜態代碼模板。和java相同,Scala也是用一個class關鍵字來標註一個類。e.g.

//A Class that constructor without arguments.nclass Sample {n}n//A Class that constructor with arguments.nclass Point(var x: Int, var y: Int) {n def move(dx: Int, dy: Int): Unit = {n x = x + dxn y = y + dyn }n override def toString: String =n "(" + x + ", " + y + ")"n}n

與java不同的是,當需要一個有參的構造函數時可以在類名後緊跟著一個小括弧中標明。當需要多個構造函數時,定義def this 方法,此外在這個方法中要調用主構造函數。

class Point(var x: Int, var y: Int) {n//Other a constructorn def this(x:Int){n//This is a must.n this(x:Int,0)n }ndef move(dx: Int, dy: Int): Unit = {n x = x + dxn y = y + dyn }noverride def toString: String =n"(" + x + ", " + y + ")"n}n

繼承類,與Java相同使用extends關鍵字來標註,如果需要調用超類的主構造函數可以在超類後面的小括弧中註明。super關鍵字是用來調用超類方法的。標註override關鍵字來表示覆蓋了超類的方法。

class ArrayElement(e: Array[String]) {n def width = e.lengthn def sayOK():String={n "OK"n }n}nclass LineElement(s: String) extends ArrayElement(Array(s)) {n override def width = s.lengthn override def sayOK(): String ={n super.sayOK()n }n}n

如果不希望被其他類繼承,可以用sealed關鍵字標註(類似Java 的final)。但是,如果兩個類在同一個.scala文件中,即使標註sealed也可以被繼承。但是類成員方法和Java相同也用final來標明。

sealed class Sample(x: Int) {n val _x = x;n}n//////////////////////////////////////nclass Math(x: Int) {n val _x = x;nn final def square(): Int = {n _x * _xn }n}n

單例對象

當我們希望,一個類只有一個實例時。我們可以用object關鍵字來代替class來標註一個類。被object標註的類不可以被繼承,不允許有構造函數。

object Sample {n}n

單例類與類同名時,這個單例對象被稱為這個類的伴生對象,而這個類被稱為這個單例對象的伴生類。伴生類和伴生對象要在同一個源文件中定義,伴生對象和伴生類可以互相訪問其私有成員。不與伴生類同名的單例對象稱為孤立對象。

object Sample{ndef apply=new Samplen}nclass Sample{n}n

case 類

使用case class修飾的類稱為樣本類。這種類可以讓Scala編譯器自動為類添加一些便捷設定。首先,它會添加與類同名的工廠方法(不用new關鍵字即可實例化,e.g. "val x = Array(1)")。其次,所有構造函數參數,自動成為成員變數。再次,添加了toString、hashCode和equals的天然實現。最後,成員變數全部默認只讀(Only get),如需set方法,把構造函數中的參數用var修飾即可。(PS:在模式匹配中有重要意義)

abstract case class fruit()n//A color is only read, The weight both readable and writablencase class Watermelon (var weight:Float,color:Int) extends fruitncase class Pitaya(area:String) extends fruitn

特質

類似Java的interfacetrait是用來裝封一些方法的代碼模板。不同的地方是,trait可以實現一些方法。trait也是緊跟類名用extends關鍵字來標註,如果有多個trait需要實現則用with關鍵字來分隔,當一個類要繼承一個類並實現多個trait時,需要用extends來標註繼承類,用with來標註特質。

trait Example{n//unimplementedn def abs(i:Int):Intn//Implementedn def sqrt(i:Int):Double={n math.sqrt(i)n }n}n-----------------------------------------nclass Father{n}ntrait Manager{n}ntrait Athlete{n n}nclass Self extends Father with Manager with Athlete{n n}n

泛型

Scala也支持泛型(參數化類型),用「[]」標識。

abstract class Generic[T,V]{nval c:Tn def get():Vn}n

協變

class Generic[+T](o:T){n val c:T=on}nval g = new Generic[AnyRef]("String")n

T或T的子類型

逆變

case class Parent()ncase class Children() extends Parentnclass Generic[-T](o: T) {n def g(t: T) = {}n}nval c = Parent()nval g = new Generic[Parent](c)nval g2: Generic[Children] = gn

T或T的父類型

下界

class GrandFathernclass Father extends GrandFathernclass Children extends Fathernclass Generic[T >: Father](val t:T) {n def g() = {print(this.t)}n}nval generic = new Generic[GrandFather]( new Father())ngeneric.g()n

T必須是Father的父類

上界

class GrandFathernclass Father extends GrandFathernclass Children extends Fathernclass Generic[T <: Father](val t:T) {ndef g() = {print(this.t)}n}nval generic = new Generic[Children]( new Children())ngeneric.g()n

T必須是Father的子類

View Bound

import scala.language.implicitConversionsnclass Bird {ndef sing = {}n}nclass Toy {}nclass Consumer() {ndef use[T <% Bird](t: T) = t.singn}nclass Test extends App {nimplicit def toy2Bird(t: Toy) = new Birdnval c = new Consumer()nc.use(new Toy)n}n

view bounds(視界),<%比<:適用的範圍更廣,除了所有的子類型,還允許隱式轉換過去的類型。

Context Bound

//Implicitly declarationnimplicit val c = new Comparator[Int]{n override def compare(a:Int, b:Int) = a - bn}nndef max[T](a: T, b: T)(implicit cp: Comparator[T]) = {n if (cp.compare(a, b) > 0) a else bn}n//Context Bound,More simplifiedndef max[T : Comparator] (a:T, b:T) = {n val cp = implicitly[Comparator[T]]n if( cp.compare(a,b)>0) a else bn}n

context bound是隱式參數的語法糖,表示存在一個 Comparator[T]類型的隱式值。


推薦閱讀:

「這一夜,數據死了」——總統大選給數字時代的一堂課
「現有人工智慧都是二流的」
全域旅遊時代帶來全域數據,行業自身得有桿秤
谷歌大神帶你十分鐘看懂TensorFlow
守著「偽需求」閉門造車,還談什麼大數據價值變現!

TAG:Scala | 大数据 |