在对象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))
来解决这个问题。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()似乎可以解决问题 - 是否有更好的解决方案?这个解决方案有什么问题吗?)
这是一个完整的可编译示例,简化了我的实际代码,试图显示最小问题。
{{1}}
答案 0 :(得分:4)
正如Daniel Sobral在评论中所解释的那样,这种情况发生了,因为“编译器看到一个参数,两个应用可能需要一个参数的方法,而且传递的参数都不适合。然后放弃考虑其他任何事情,因为它不知道尝试哪种方法。如果传递了两个参数,则丢弃一个apply,编译器会查找使另一个参数生效的隐式转换。“
(请记住,编译器会自动定义一个apply
,因为您正在定义case class
。)
如果你改为编写,隐式转换就可以了:
object ValueSet {
def fromPairs(pairs: (String, ValueBase)*): ValueSet = {
ValueSet(pairs.map(p => ValuePair(p._1, p._2)).toList)
}
}
object Sample {
implicit def int2value(i: Int): ValueInt = ValueInt(i)
implicit def string2value(s: String): ValueString = ValueString(s)
/* These samples show the goal, to construct the sets
* in a nice Map-literal sort of style
*/
val oneInt = ValueSet.fromPairs("a" -> 1)
val oneString = ValueSet.fromPairs("b" -> "c")
val twoInt = ValueSet.fromPairs("d" -> 2, "e" -> 3)
val twoTypes = ValueSet.fromPairs("f" -> 4, "g" -> "quick brown fox")
}
不完全是你所希望的,我知道......