您获得+ 运算符为您工作而无需明确使用.toString 的原因如下:What Scala feature allows the plus operator to be used on Any?。 Predef 中的这些额外隐含是 scala 中许多问题的根源,但很难摆脱这些遗留问题。
要找出 addTwoThings("1",2) 工作的原因 - 让我们重写它以获得 S 的准确推断:
scala> def addTwoThings[S](item1:S, item2:S): S = item1
addTwoThings: [S](item1: S, item2: S)S
scala> addTwoThings(1, "1")
res5: Any = 1
您可以注意到 S = Any 类型被推断为常见类型。
所以,这里有几个解决方案:
1) 如果您可以在方法的签名中允许两个类型参数,则解决方案如下:
def addTwoThings[S1, S2](item1:S1, item2:S2)(implicit ev: S1 =:= S2, ev2: S2 =:= S1) = {
item1 + " | " + item2
}
注意:ev2 对于检查可能是多余的,但它提供了更完整的相等性,请参阅Scala: generic method using implicit evidence doesn't compile
实验:
scala> addTwoThings(1, "1")
<console>:18: error: Cannot prove that Int =:= String.
addTwoThings(1, "1")
^
scala> addTwoThings("2", "1")
res11: String = 2 | 1
2) 或者您可以使用 Evidence that types are not equal in Scala 排除 Any/AnyRef(所有事物的通用超类型):
trait =:!=[A, B]
implicit def neq[A, B] : A =:!= B = new =:!=[A, B] {}
implicit def neqAmbig1[A] : A =:!= A = ???
implicit def neqAmbig2[A] : A =:!= A = ???
def addTwoThings[S](item1:S, item2:S)(implicit ev: S =:!= Any, ev2: S =:!= AnyRef): S = item1
实验:
scala> addTwoThings(1, "1")
<console>:18: error: ambiguous implicit values:
both method neqAmbig1 of type [A]=> =:!=[A,A]
and method neqAmbig2 of type [A]=> =:!=[A,A]
match expected type =:!=[Any,Any]
addTwoThings(1, "1")
^
scala> addTwoThings(1, 1)
res7: Int = 1
注意:这种方法不需要精确的类型相等,所以如果B1 <: B2 - addTwoThings(b1, b2) - 仍然有效。它仅保护您免受不相关的类型层次结构的影响(这可能很有用)。在实践中,!= Any 没有!= AnyRef 不会在object A; object B; addTwoThings(B, A) 上给你错误。
注意2:编译器提供的错误很难阅读,更多信息在这里 - How can I customize Scala ambiguous implicit errors when using shapeless type inequalities
3) 另一种方法是柯里化:
def addTwoThings[S](item1:S)(item2:S) = ""
实验:
scala> addTwoThings(1)(1)
res8: String = ""
scala> addTwoThings(1)("1")
<console>:18: error: type mismatch;
found : String("1")
required: Int
addTwoThings(1)("1")
^
类型推断不会寻找柯里化参数的常见超类型(您可以阅读更多here)