假設您想要將一些方法添加到所有智能類型。這可以是這樣的:在Scala中隱式轉換泛型和非泛型子類型
import collection.generic.CanBuildFrom
class Foo[P, S[X] <: Iterable[X]](val s : S[P]) {
def bar(j : P)(implicit bf : CanBuildFrom[S[P],P,S[P]]) : S[P] = {
val builder = bf(s)
builder ++= s
builder += j
builder.result
}
def oneBar(j : P)(implicit bf : CanBuildFrom[S[P],P,S[P]]) : P = bar(j).head
}
implicit def iter2foo[P, S[X] <: Iterable[X]](s : S[P]) = new Foo[P,S](s)
現在,類似的代碼
println(Seq(1,2,3,4) bar 5)
編譯和執行順利。然而,
println((1 to 4) bar 5)
導致
error: value bar is not a member of scala.collection.immutable.Range.Inclusive
with scala.collection.immutable.Range.ByOne
我想這可能是因爲隱式轉換需求(?)是參數的類型有一個類型參數(Range
還沒有)。但是
implicit def iter2foo[P, S <: Iterable[P]](s : S) = new Foo[P,Iterable](s)
不會改變任何東西。請注意0延伸Iterable[Int]
。
我在做什麼錯?我怎樣才能寫出一個適用於所有Iterable
的子類型的隱式轉換?
編輯:我只是注意到按預期(上REPL)更簡單
implicit def iter2foo[P](s : Iterable[P]) = new Foo[P,Iterable](s)
作品。還是呢?這種解決方案有什麼缺點嗎?
編輯2:的缺點是的bar
靜態結果類型只會Iterable[P]
,而不是更具體的類型。雖然構建的集合具有正確的(實際)類型。
它不應該爲'String'工作(因爲它是唯一可見的是'Seq'),但它應該'Map','範圍「和其他可憐的生物。如果這是一個問題,爲什麼第二個版本不起作用?我怎樣才能定義第二個隱式轉換,它捕獲所有不帶類型參數的'Iterable'的子類型? – Raphael 2011-03-03 18:04:19
@update:我明白了。然而,我不清楚爲什麼推理者不考慮超類型。由於你不能用不同的參數(?)擴展相同的特徵,這應該產生明確的結果。至於我更簡單的版本,它創建了正確的(動態)類型的集合,但只能靜態地輸入「Iterable」。那就是你得到'CanBuildFrom'的「底層」優勢,但不是打字優勢。 – Raphael 2011-03-04 11:13:41
我已經擴展了我的答案,以更詳細地解釋。 – 2011-03-04 11:36:27