[英]Existential types and type members
假設我有一個帶有類型參數的特征:
trait A[T]
我可以使用存在類型來編寫一個方法,該方法將采用所有具有相同T
的A
的集合:
def foo(as: Seq[A[X]] forSome { type X }) = true
請注意,這與以下內容不同:
def otherFoo(as: Seq[A[X] forSome { type X }]) = true
或等效的:
def otherFoo(as: Seq[A[_]]) = true
在這些情況下,存在體的范圍在Seq
內部,因此A
s可以具有不同的T
s。 使用我原來的foo
(對Seq
的存在范圍),以下情況很好:
foo(Seq(new A[Int] {}, new A[Int] {}))
但是使類型參數不同並且不能編譯:
scala> foo(Seq(new A[Int] {}, new A[String] {}))
<console>:10: error: type mismatch;
found : Seq[A[_ >: java.lang.String with Int]]
required: Seq[A[X]] forSome { type X }
foo(Seq(new A[Int] {}, new A[String] {}))
^
這一切都非常簡單。
現在假設我有類似成員的類似特征而不是類型參數:
trait B { type T }
我可以編寫一個只帶有一些指定T
的B
的方法:
scala> def bar[X](b: B { type T = X }) = true
bar: [X](b: B{type T = X})Boolean
scala> bar[Int](new B { type T = Int })
res5: Boolean = true
scala> bar[String](new B { type T = Int })
<console>:10: error: type mismatch;
found : java.lang.Object with B
required: B{type T = String}
bar[String](new B { type T = Int })
^
同樣,這完全符合您的預期。
當我們嘗試編寫上述foo
的等價物,但對於類型成員,事情變得奇怪。
scala> def baz(bs: Seq[B { type T = X }] forSome { type X }) = true
baz: (as: Seq[B{type T = X}] forSome { type X })Boolean
scala> baz(Seq(new B { type T = Int }, new B { type T = String }))
res7: Boolean = true
最后一行編譯對我來說毫無意義。 我告訴它我希望所有類型的成員都是一樣的。 我的foo
表明我可以為類型參數執行此操作, bar
顯示我可以基於其類型成員約束類型。 但我無法將兩者結合起來。
我在2.9.2和2.10.0-M5上試過這個。
這個問題的靈感來自於這個問題,我的第一個想法是,哦,只使用存在類型(暫時擱置一個問題, 似乎不可能將存在類型轉換為重復參數類型的范圍 ,這將是方便的):
def accept(rs: Seq[RList[Int] { type S = X }] forSome { type X }) = true
但這實際上並不起作用 - 你得到了與上面簡化例子中相同的奇怪結果。
我終於解決了(至少我希望如此)。 讓我們以另一種方式做。 我們建立我們的特質:
scala> trait B {type T}
defined trait B
我們嘗試構建一個B
序列:
scala> Seq(new B {type T = Int}, new B {type T = String})
res0: Seq[B{type T >: String with Int}] = List($anon$1@592b12d, $anon$2@61ae0436)
該死的,它的作品! 好吧,我們沒有type T
的相等,但讓我們玩它:
scala> res0 : (Seq[B {type T = X}] forSome {type X >: String with Int})
res1: Seq[B{type T = X}] forSome { type X >: String with Int } = List($anon$1@592b12d, $anon$2@61ae0436)
它更接近了。 沒有等待,它不是更接近,它比你提出的baz
參數更好 ,我們不僅提供原始類型,我們也有一個上限! 因此,我們可以清楚地將它傳遞給baz
。 這就是它無法按預期工作的原因。
在你的例子中:
scala> def baz(bs: Seq[B { type T = X }] forSome { type X }) = true
告訴編譯器函數baz采用特征B的Seq。 特征B碰巧采用類型成員T,但就編譯器而言,即使B類型成員T的類型不相同,函數baz也可以采用特征B的Seq。 如果你想讓函數baz采用具有相同類型成員的特征B的Seq,你需要告訴編譯器如下:
scala> def baz[X](bs: Seq[B { type T = X }]) = true
baz: [X](bs: Seq[B{type T = X}])Boolean
scala> baz[Int](Seq(new B { type T = Int }, new B { type T = String }))
<console>:10: error: type mismatch;
found : java.lang.Object with B
required: B{type T = Int}
baz[Int](Seq(new B { type T = Int }, new B { type T = String }))
^
scala> baz[Int](Seq(new B { type T = Int }, new B { type T = Int }))
res10: Boolean = true
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.