Scala的語法很多,有些人認爲過於繁瑣,有些人卻認爲正是因爲繁瑣,所以才讓這門語言嚴謹和強大。
例如在翻閱Scala資料或者查看Scala源碼的時候,經常會看到“<:”和“>:”,這是什麼鬼?下面我就來探討一下這兩個符號的用法:
“<:”符號
我們定義一個類:“Earth”
class Earth {
def sound(){
println("hello !")
}
}
我們定義了一個子類:“Animal”
class Animal extends Earth{ override def sound() ={ println("animal sound") } }
然後 ,還有Animal 的一個子類 “Bird”
class Bird extends Animal{ override def sound()={ print("bird sounds") } }
最後,又定義了一個函數:
def biophony[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
“>:”符號
我們把“<:”換成了“>:”
def biophony[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處理!
更多精彩內容,請關注我的微信公衆賬號 互聯網技術窩