在對象ValueSet上,我有apply(pairs : (String, ValueBase)*)
以及從Int和String到ValueBase的隱式轉換。如果我申請ValueSet("a" -> 1, "b" -> 2)
那麼(String, Int)
對轉換爲(String, ValueBase)
,它工作正常。如果我只申請一對,ValueSet("a" -> 1)
則表示沒有申請(String,Int)
的超載,即它不會隱式轉換。我可以通過添加apply[V <% ValueBase](p : (String, V))
來解決這個問題,它可以在一對情況下工作。爲什麼Scala隱式轉換工作有兩個參數,但沒有一個?
爲什麼apply(pairs : (String, ValueBase)*)
只能用一對?
(獎金的問題:增加額外的應用()似乎解決的問題 - 有沒有更好的解決辦法是有什麼問題該解決方案?)
下面是一個完整編譯的例子,從我的實際代碼簡化試圖展示最小的問題。
class ValueBase
case class ValueInt(val value : Int) extends ValueBase
case class ValueString(val value : String) extends ValueBase
case class ValuePair(val key : String, val value : ValueBase)
case class ValueSet(val value : List[ValuePair]) extends ValueBase
object ValueSet {
def apply(pairs : (String, ValueBase)*) : ValueSet = {
ValueSet(pairs.map(p => ValuePair(p._1, p._2)).toList)
}
/* Commenting out this apply() means single-pair
* ValueSet("a" -> 1)
* will not compile, error is:
* overloaded method value apply with alternatives: (value: List[ValuePair])ValueSet <and> (pairs: (String, ValueBase)*)ValueSet cannot be applied to ((java.lang.String, Int))
* Why does (String,Int) implicit convert to (String,ValueBase) if there are two args but not if there's one?
* Why do I need this apply()?
*/
def apply[V <% ValueBase](p : (String, V)) : ValueSet = {
ValueSet(List(ValuePair(p._1, p._2)))
}
}
object Sample {
implicit def int2value(i : Int) = ValueInt(i)
implicit def string2value(s : String) = ValueString(s)
/* These samples show the goal, to construct the sets
* in a nice Map-literal sort of style
*/
val oneInt = ValueSet("a" -> 1)
val oneString = ValueSet("b" -> "c")
val twoInt = ValueSet("d" -> 2, "e" -> 3)
val twoTypes = ValueSet("f" -> 4, "g" -> "quick brown fox")
/* Taking ArrowAssoc out of the picture and typing "Pair"
* explicitly doesn't seem to matter
*/
val oneInt2 = ValueSet(Pair("a", 1))
val twoTypes2 = ValueSet(Pair("f", 4), Pair("g", "quick brown fox"))
}
有趣。我不明白爲什麼編譯器定義的apply()會混淆這個: - /它似乎不像Pair(「a」 - > 1)應該有任何方式成爲List [ValuePair],所以編譯器定義不應該使用apply()...是否給出兩個single-arg apply()重載的問題,編譯器會放棄隱式轉換?但是爲什麼添加額外的apply()修復它 - 可能是因爲它不需要隱式轉換來匹配超載,這是由於「<%」? – 2011-05-03 14:31:04
@Havoc Jean-Philippe將它擊中。這裏的問題是編譯器會看到一個參數,兩個'apply'方法可能需要一個參數,並且傳遞的參數都不適合。它然後*放棄*考慮其他任何事情,因爲它不知道要嘗試哪種方法。如果傳遞了兩個參數,那麼放棄一個'apply'並且編譯器尋找使另一個工作的隱式轉換。 @Jean,你能用這些信息補充答案嗎? – 2011-05-03 14:57:29
@浩瀚我不完全知道。 Scala規範重載分辨率的頁面並不是一個簡單的部分。不知道爲什麼額外的'apply'修復它,但請記住'T <%S'的視圖是代表從'T'到'S'轉換的隱式參數的縮寫,所以它也是在編譯時需要隱式查找。 – 2011-05-03 14:57:39