Scala中那些令人头痛的符号
Scala中符號語法糖
初學(xué)Scala看到那些稀奇古怪的符號(e.g. ??<: , >: , ?<% ?, ?=:= , <:< , ?<%<, ?+T, -T ),總讓人摸不著頭腦,Scala創(chuàng)造這些語法糖究竟是要做甚?再參詳了幾篇文章(具體見參考文獻)后,作者終于可以摸著一些皮毛了,于是決定記錄下來。
1. 上下界約束符號 <: 與 >:
這對符號個人覺得是里面最好理解的了,這對符號用于寫范型類/函數(shù)時約束范型類型。
先舉個栗子:
def using[A <: Closeable, B](closeable: A) (getB: A => B): B =
? try {?
? ? getB(closeable)
? } finally {
? ? closeable.close()?
? }
例子中A <: Closeable(java.io.Cloaseable)的意思就是保證類型參數(shù)A是Closeable的子類(含本類),語法“A <: B"定義了B為A的上界;同理相反的A>:B的意思就是A是B的超類(含本類),定義了B為A的下界。
其實<: 和 >: 就等價于java范型編程中的 extends,super(PS: 說起來C#中只有where A:B形似的上界約束,怎么沒有下界約束呢?求高人指教)
2. 協(xié)變與逆變符號+T, -T
“協(xié)變”是指能夠使用與原始指定的派生類型相比,派生程度更大的類型。e.g. String => AnyRef
“逆變”則是指能夠使用派生程度更小的類型。e.g. AnyRef => String
【+T】表示協(xié)變,【-T】表示逆變
3. view bounds(視界) 與 <%
<%的意思是“view bounds”(視界),它比<:適用的范圍更廣,除了所有的子類型,還允許隱式轉(zhuǎn)換過去的類型
def method [A <% B](arglist): R = ...
等價于:
def method [A](arglist)(implicit viewAB: A => B): R = ...
或等價于:
implicit def conver(a:A): B = …
?
def method [A](arglist): R = ...
<%?除了方法使用之外,class聲明類型參數(shù)時也可使用:
scala> class A[T <% Int]
defined class A
但無法對trait的類型參數(shù)使用?<%,
scala> trait A[T <% Int]
<console>:1: error: traits cannot have type parameters with context bounds `: ...' nor view bounds `<% ...'
4. 廣義類型約束符號 =:=, <:<, ?<%<
這些被稱為廣義的類型約束。他們允許你從一個類型參數(shù)化的class或trait,進一步約束其類型參數(shù)之一。下面是一個例子:
case class Foo[A](a:A) { // 'A' can be substituted with any type
? ? // getStringLength can only be used if this is a Foo[String]
? ? def getStringLength(implicit evidence: A =:= String) = a.length
}
這個隱式的參數(shù)?evidence?由編譯器提供,A =:=String表示證明A是String類型(PS:即使A可以隱式轉(zhuǎn)換成String類型也不行),因此參數(shù)a就可以調(diào)用a.length 而編譯器不會報錯。
我們可以如下使用:
scala> Foo("blah").getStringLength
res0: Int = 4
一旦我們使用其他不能轉(zhuǎn)換成String類型的參數(shù),就會報錯,如下:
scala> Foo(123).getStringLength
<console>:10: error: Cannot prove that Int =:= String.
? ? ? ? ? ? ? Foo(123).getStringLength
? ? ? ? ? ? ? ? ? ? ? ?^
scala> implicit def charSeq2String(s: Seq[Char]) = s.mkString
charSeq2String: (s: Seq[Char])String
?
scala> Foo(Seq[Char]('a','b','c')).getStringLength
<console>:11: error: Cannot prove that Seq[Char] =:= String.
? ? ? ? ? ? ? Foo(Seq[Char]('a','b','c')).getStringLength
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ^
<:<?和?<%<?使用類似, 有細微不同:
A =:= B?表示 A 必須是 B 類型
A <:< B?表示 A 必須是B的子類型 (類似于簡單類型約束?<:)
A <%< B?表示 A 必須是可視化為?B類型, 可能通過隱式轉(zhuǎn)換 (類似與簡單類型約束?<%)
5. 傳名調(diào)用(call-by-name)符號: => type
傳名調(diào)用 (Call by name)[編輯]
在“傳名調(diào)用”求值中,根本就不求值給函數(shù)的實際參數(shù) — 而是使用避免捕獲代換把函數(shù)的實際參數(shù)直接代換入函數(shù)體內(nèi)。如果實際參數(shù)在函數(shù)的求值中未被用到,則它永不被求值;如果這個實際參數(shù)使用多次,則它每次都被重新求值。
傳名調(diào)用求值超過傳值調(diào)用求值的優(yōu)點是傳名調(diào)用求值在一個值存在的時候總是生成這個值,而傳名調(diào)用可能不終止如果這個函數(shù)的實際參數(shù)是求值這個函數(shù)所不需要的不終止計算。反過來說,在函數(shù)的實際參數(shù)會用到的時候傳名調(diào)用就非常慢了,這是因為實踐中幾乎總是要使用如?thunk?這樣的機制。
傳需求調(diào)用 (Call by need)
“傳需求調(diào)用”是傳名調(diào)用的記憶化版本,如果“函數(shù)的實際參數(shù)被求值了”,這個值被存儲起來已備后續(xù)使用。在“純”(無副作用)設(shè)置下,這產(chǎn)生同傳名調(diào)用一樣的結(jié)果;當(dāng)函數(shù)實際參數(shù)被使用兩次或更多次的時候,傳需求調(diào)用總是更快。
Scala中call by name使用:
object TargetTest2 extends Application {
? def loop(body: => Unit): LoopUnlessCond =
? ? new LoopUnlessCond(body)
? protected class LoopUnlessCond(body: => Unit) {
? ? def unless(cond: => Boolean) {
? ? ? body
? ? ? if (!cond) unless(cond)
? ? }
? }
? var i = 10
? loop {
? ? println("i = " + i)
? ? i -= 1
? } unless (i == 0)
}
上面的程序運行結(jié)果是
i = 10
i = 9
i = 8
i = 7
i = 6
i = 5
i = 4
i = 3
i = 2
i = 1
6.參考文獻
1.http://stackoverflow.com/questions/3427345/what-do-and-mean-in-scala-2-8-and-where-are-they-documented
2.http://stackoverflow.com/questions/7167662/how-to-express-implicit-conv-string-a-as-a-view-bound
3.http://hongjiang.info/scala-type-system-view-bounds/
4.http://zh.wikipedia.org/wiki/%E6%B1%82%E5%80%BC%E7%AD%96%E7%95%A5#.E4.BC.A0.E5.90.8D.E8.B0.83.E7.94.A8_.28Call_by_name.29
---------------------?
作者:bobozhengsir?
來源:CSDN?
原文:https://blog.csdn.net/bobozhengsir/article/details/13023023?
版權(quán)聲明:本文為博主原創(chuàng)文章,轉(zhuǎn)載請附上博文鏈接!
總結(jié)
以上是生活随笔為你收集整理的Scala中那些令人头痛的符号的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Scala学习之特殊符号,及函数
- 下一篇: Facebook 开源了一整套重要的 L