scala 上界 <:, 下界>:, 视界 <%, 边界 :, 协变 +T, 逆变-T
概述
上界 (<:) 下界(>:) 是類型約束范疇,用來約束對象的子類是誰,父類是誰
協變 (+T) 逆變(-T)是泛型范疇,主要用于集合類型變量賦值。
視界 (<%) 邊界( :)是隱式調用的簡寫。
上界 (<:) 下界(>:)
上界:要求對象必須是某一個對象的子類,因為子類會繼承父類的屬性和方法,所以父類的方法和屬性這路都可以用。
trait A {def func()}class B extends A {override def func(): Unit = {println("i am b")}}class C extends A {override def func(): Unit = {println("i am c")}}def test[T <: A](obj: T): Unit = {obj.func()}test(new B()) // i am btest(new C()) // i am c下界:要求對象必須是某一個對象的父類。主要用在已知某一個具體類型,但是要給它賦值給另一個變量,該變量必須是具體類型的父類型才行。
舉例:
對于下面的例子,我們要把元素B放到一個集合中,這個集合必須是類型B父類容器才行。這里就是B是已知類型,集合類型未知。
協變 (+T) 逆變(-T)
逆變協變指的是類型T和包裝類型直接的關系。
有兩個類如下所示:
假設有個包裝類型F[T]
class F[T]現在我們生產一個F[B]實例,然后賦值給F[A]類型的變量.就會報錯。因為F[B]并不是F[A]的子類。
val a:F[A] = new F[B]() // error所以這個時候才會需要逆變和協變。
協變:子類的包裝類型也是父類包裝類型的子類
逆變:子類的包裝類型是父類包裝類型的父類
class G[-T] // 逆變val b: G[B] = new G[A]() // 正確一個比較經典的例子是:scala 函數的定義.scala中所有的函數,參數都是逆變的,返回值都是協變的。 trait Function[-T1,+T2].也就是說一個函數要賦值給一個函數類型變量。這個函數的參數必須是函數變量參數的父類,返回值必須是函數變量返回值的子類。
trait A {def func()}class B extends A {override def func(): Unit = {println("i am b")}}class C extends B {}val func: B => B = (a: A) => { new C() } // 把 A=>C類型的函數賦值給B=>B類型的變量視界 <%, 邊界 :
視圖和邊界看到的比較多,但是功能比較強大,也容易被誤解。比如 ( : )就經常會被誤以為是上界和下屆的一種。
視界 <%
視界只是一種隱式類型函數的簡寫。如果我們需要一個Fruits類型的隱式參數,但是我們只有一個 T 類型,這時就可以用視界。他要求想使用這個函數,必須提供一個由T => Fruits的隱式調用。 比如下面:
scala> case class Fruits(name: String) defined class Fruitsscala> def getFruits[T <% Fruits](value: T): Fruits = value getFruits: [T](value: T)(implicit evidence$1: T => Fruits)Fruits等價于scala> def getFruits[T](value: T)(implicit evidence: T => Fruits): Fruits = evidence(value) getFruits: [T](value: T)(implicit evidence: T => Fruits)Fruits邊界 :
邊界相對來將應用場景比較多一些。下面有個函數anothr,需要一個隱式參數。我們在func中調用了這個方法,但是我們并沒有提供隱式參數。這就和視圖有點類似了。在視圖中要求傳入一個隱式函數,但這里是要求傳入一個隱式類型。
class F[T]def another[T](elem: T)(implicit f: F[T]) = {// do nothing }def func[T: F](elem: T): Unit = {another(elem) }scala> def func[T: F](elem: T): Unit = {another(elem)}func: [T](elem: T)(implicit evidence$1: F[T])Unit // 使用 scala> func(1)(new F[Int]()) 或則 scala> func(1)(new F()) //自行推斷有一個比較經典的例子,利用這個方法可以實現隱式泛型
import scala.reflect.runtime.universe._typeOf函數需要傳入一個隱式類型TypeTag[T] // def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpedef getTypeTag[T: TypeTag](obj: T) = typeOf[T] // 我們調用的時候也沒有傳入隱式類型,因為scala運行環境中會自定存儲。 getTypeTag(1)總結
以上是生活随笔為你收集整理的scala 上界 <:, 下界>:, 视界 <%, 边界 :, 协变 +T, 逆变-T的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows To Go常见问题
- 下一篇: python爬虫模拟登陆腾讯课堂