2014-07-10 79 views
4

我讀Demystifying Scala Type System,在17幻燈片有一個片段:混亂理解Scala的束縛

class Test[+A] { 
    def test[B >: A](b: B): String = b.toString 
} 

幻燈片說的方法測試將接受A型或超A型的,但似乎我能通過任何類型來測試。

vat t = new Test[Int] 
t.test("foo") 
t.test(List(1, 2, 3)) 

我在閱讀Scala編程時遇到同樣的困惑。

回答

6

這裏要記住的重要一點是,Any是超類型的任何類型的,即

Any >: A 

特別是,假設

val t = new Test[Int] 

這是AInt。現在我們調用

t.test("foo") 

"foo"String類型,但字符串是Any亞型,因此可以認爲是這樣的,因此test[B >: A](b : B)可以用b"foo"BAny調用。

下面的例子應該說明這一點,考慮

class Test[+A](a : A) { 
    def test[B >: A](b : B) : (A,B) = (a,b) 
} 
現在

,使用

val t = new Test(3) 
val x = t.test("foo") 

我們得到

x: (Int, Any) = (3,foo) 

最後,補充一些細節,斯卡拉不會總是挑Any,但最不常見的超類型AB。這恰好是AnyIntString(見http://www.scala-lang.org/old/node/128),但可能是一些其他的例子不同,例如,對於

val s = new Test(Nil) 
val y = s.test("foo") 
val z = s.test(List(1)) 

我們會得到

y: (scala.collection.immutable.Nil.type, java.io.Serializable) = (List(),foo) 
z: (scala.collection.immutable.Nil.type, List[Int]) = (List(),List(1)) 

另外請注意,下限不不妨礙通過亞型A

scala> val a = new Test(new AnyRef()) 
a: Test[java.lang.Object] = [email protected] 

scala> a.test("foo") 
res6: (java.lang.Object, java.lang.Object) = ([email protected],foo) 

所以,問題是,什麼是較低類型邊界有用嗎?一個可能的答案是它們可以用於「控制」「輸出」位置的類型,如通常用於協變類型參數的那樣,參見例如http://docs.scala-lang.org/tutorials/tour/lower-type-bounds.html粗略地說,當將元素附加到A類型的(協變)列表時,您想要確保結果列表是「至少」A類型。 (我很抱歉這部分內容是手動的,但由於它超出了原始問題的範圍,因此我只想給出一個簡要的概念,說明爲什麼需要它們,爲了得到完整的答案,最好創建一個新的問題)

+0

在我的例子中,如果每個類型都可以傳遞給測試方法,爲什麼我們需要一個綁定呢?爲什麼它是一個上限而不是下限? – user2018791

+0

@ user2018791您不能傳遞A的子類型。 –

+0

@ user2018791我在下限有用時添加了一個簡短解釋,但是最好是專門提出一個新問題。 – godfatherofpolka

0

該參數可以接受任何類型,因爲任何。但是,我不認爲這個例子非常清楚。如果你把這個片段到工作表

如果定義的返回類型爲B的東西,你會看到的問題

class Test[+A] { 
    def test[B >: A](b: B): B = b 
} 


class A 

class B extends A 

val test = new Test[B] 

val t = test.test("test") 

返回類型不串,是對象。所以基本上,它會丟失類型參考。

我們需要這樣定義的原因是A是covariant。在這種情況下,它只能用於返回類型而不是參數因爲的定義功能1 [-A,+ B]。如果使用DEF試驗(B:A).....它將有編譯錯誤:

協變型在逆變位置發生在值b DEF試驗(B:A):的類型的字符串= B .toString

此外,如果您想約束超類型,可以有多個選項。其中之一是使用隱式來限制類型。

class C 

class CCC extends C 

def test[B >: A](b: B)(implicit ev: B =:= C): B = b 

val test = new Test[CCC] 

test.test(new C)//ok 

test.test("123")//compilation error