[英]What is a “context bound” in Scala?
Robert的答案涵蓋了Context Bounds的技術細節。 我會告訴你我們對它們意義的解釋。
在Scala中,視圖邊界( A <% B
)捕獲“可以被視為”的概念(而上限<:
捕獲'是'的概念)。 上下文綁定( A : C
)表示“有一個”類型。 您可以閱讀有關清單的示例“ T
has a Manifest
”。 您鏈接到Ordered
vs Ordering
示例說明了差異。 一個方法
def example[T <% Ordered[T]](param: T)
說參數可以看作是Ordered
。 與之比較
def example[T : Ordering](param: T)
表示該參數具有關聯的Ordering
。
在使用方面,建立約定需要一段時間,但上下文邊界優先於視圖邊界( 現在不推薦使用視圖邊界 )。 一個建議是,當您需要將隱式定義從一個范圍轉移到另一個范圍而不需要直接引用它時,首選上下文綁定(這對於用於創建數組的ClassManifest
來說肯定是這種情況)。
另一種思考視圖邊界和上下文邊界的方法是,第一種方式是從調用者的范圍轉移隱式轉換。 第二個從調用者的范圍傳輸隱式對象。
你找到這篇文章了嗎? 它涵蓋了在數組改進的上下文中的新上下文綁定功能。
通常,具有上下文邊界的類型參數的形式為[T: Bound]
; 它與一個類型為Bound[T]
的隱式參數一起擴展為普通類型參數T
考慮方法tabulate
,該表格從在從0到給定長度的數字范圍內應用給定函數f的結果形成數組。 對於Scala 2.7,表格可以寫成如下:
def tabulate[T](len: Int, f: Int => T) = {
val xs = new Array[T](len)
for (i <- 0 until len) xs(i) = f(i)
xs
}
在Scala 2.8中,這不再可能,因為運行時信息是創建Array[T]
的正確表示所必需的。 需要通過將ClassManifest[T]
作為隱式參數傳遞給方法來提供此信息:
def tabulate[T](len: Int, f: Int => T)(implicit m: ClassManifest[T]) = {
val xs = new Array[T](len)
for (i <- 0 until len) xs(i) = f(i)
xs
}
作為簡寫形式,可以在類型參數T
上使用上下文綁定 ,給出:
def tabulate[T: ClassManifest](len: Int, f: Int => T) = {
val xs = new Array[T](len)
for (i <- 0 until len) xs(i) = f(i)
xs
}
(這是一個括號內容。請先閱讀並理解其他答案。)
Context Bounds實際上概括了View Bounds。
所以,鑒於這個代碼用View Bound表示:
scala> implicit def int2str(i: Int): String = i.toString
int2str: (i: Int)String
scala> def f1[T <% String](t: T) = 0
f1: [T](t: T)(implicit evidence$1: (T) => String)Int
這也可以用Context Bound表示,借助於表示從F
到T
類的函數的類型別名。
scala> trait To[T] { type From[F] = F => T }
defined trait To
scala> def f2[T : To[String]#From](t: T) = 0
f2: [T](t: T)(implicit evidence$1: (T) => java.lang.String)Int
scala> f2(1)
res1: Int = 0
上下文綁定必須與類型* => *
的類型構造函數一起使用。 但是類型構造Function1
是種類(*, *) => *
。 類型別名的使用部分地應用具有String
類型的第二類型參數,從而產生正確類型的類型構造函數以用作上下文綁定。
有一個建議允許您直接在Scala中表達部分應用的類型,而不使用特征中的類型別名。 然后你可以寫:
def f3[T : [X](X => String)](t: T) = 0
這是另一個括號內容。
正如Ben所指出的 ,上下文綁定表示類型參數和類型類之間的“has-a”約束。 換句話說,它表示存在特定類型類的隱式值的約束。
在利用上下文綁定時,通常需要表達隱式值。 例如,給定約束T : Ordering
,通常需要滿足約束的Ordering[T]
實例。 如此處所示 ,可以通過使用implicitly
方法或稍微有用的context
方法來訪問隱式值:
def **[T : Numeric](xs: Iterable[T], ys: Iterable[T]) =
xs zip ys map { t => implicitly[Numeric[T]].times(t._1, t._2) }
要么
def **[T : Numeric](xs: Iterable[T], ys: Iterable[T]) =
xs zip ys map { t => context[T]().times(t._1, t._2) }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.