Scala 的那些奇怪的符號 (一):“:” 作用及用法
Scala的語法很多,有些人認為過於繁瑣,有些人卻認為正是因為繁瑣,所以才讓這門語言嚴謹和強大。
例如在翻閱Scala資料或者檢視Scala原始碼的時候,經常會看到“<:”和“>:”,這是什麼鬼?下面我就來探討一下這兩個符號的用法:
“<:”符號
我們定義一個類:“Earth”
class Earth { def sound(){ println("hello !") } }
我們定義了一個子類:“Animal”
class Animal extends Earth{ override def sound() ={ println然後 ,還有Animal 的一個子類 “Bird”("animal sound") } }
class Bird extends Animal{ override def sound()={ print("bird sounds") } }最後,又定義了一個函式:
defbiophony[T <: Animal](things: Seq[T]) = things map (_.sound)
乍一看:這tm是什麼鬼?“<:”是什麼意思?
其實, 這屬於Scala泛型中的知識:上邊界和下邊界。上邊界是“<:”,下邊界是“>:”;T <: Animal的意思是:T必須是Animal的子類。這樣一來,我們再看看這個函式的意思:定義了一個叫“biophony”的函式,這個函式的引數必須傳一個集合,一個什麼樣的集合呢?Animal 子類或者是Animal的集合(包含Animal)。函式右邊就很好理解了,map中每個元素呼叫了sound方法。
知道了是什麼之後,接著呼叫就很簡單了:
biophony(Seq(new Bird, new Bird))
這樣一來就輸出:
bird sounds
bird sounds
完美!
假如因為可以包含Animal所以,這麼呼叫也可以:
biophony(Seq(new Animal, new Animal))輸出:
animal sound
animal sound
甚至可以一個Animal,一個Bird,多型嘛!
biophony(Seq(new Animal, new Bird))
輸出:
animal sound
bird sounds
但是,這樣就不可以了:
biophony(Seq(new Earth, new Earth))輸出:
報錯!
Scala的定義了一個“界限”來規定泛型可以適用的在繼承關係中的範圍,“<:”是上限,表示不超過XXX
“>:”符號
我們把“<:”換成了“>:”
defbiophony[T >: Animal](things: Seq[T]) = things map (_.sound())不對這怎麼還報紅了呢?細細想來,Animal的父類的話,不能確定能不能有sound()方法呀,因為父類太多了,Object還是呢。報錯也正常,我們就直接返回 things吧
def biophony[T >: Animal](things: Seq[T]) = things好了,這下好了,不報紅了,我們傳一個Animal的父類“Earth”的佇列,然後沒個元素呼叫“sound()”方法
biophony(Seq(new Earth, new Earth)).map(_.sound())輸出:
hello !
hello !
之前的結論,呼叫Animal也應該是可以的:
biophony(Seq(new Animal, new Animal)).map(_.sound())
輸出:
animal sound
animal sound
好的,也是正確的。假如我們傳Animal子類Bird看看會不會報錯
biophony(Seq(new Bird, new Bird)).map(_.sound())輸出:
bird sounds
bird sounds
居然不報錯!還運行了!這是怎麼回事??
我們看一下傳Bird後的返回值是什麼:
是Animal !真相大白了,由於Bird是子類,Scala把Bird當做Animal來處理了。也就是說,“>:”的時候,傳任何引數都可以,但是返回值回有所不同,Animal的子類都會統一按照Animal來處理!
那我們傳一個和Animal毫不相關的類,會出現什麼情況呢?
class Moon {
}
寫了一個Moon,然後按照如下文傳參呼叫
biophony(Seq(new Moon, new Moon))不報錯!
我們看一下返回值:
Object!Scala把它看做了Object。也就是說,可以隨便傳!只不過和Animal直系的,是Animal父類的還是父類處理,是Animal子類的按照Animal處理,和Animal無關的,一律按照Object處理!