在对象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