我在scala中有以下多态方法:
def addTwoThings[S](item1:S, item2:S) =
{
item1 + " | " + item2
}
如果我已经指定item1和item2应该是相同类型" S"以下,则编译很好。我是否需要用隐含证据做些什么?
要说清楚,我实际上希望编译器抱怨他们不是同一类型,但它似乎允许我继续,这让我很困惑。感谢。
println(addTwoThings("1",2))
答案 0 :(得分:3)
此处描述了+
运算符在不使用.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)
不会在def addTwoThings[S](item1:S)(item2:S) = ""
上给您错误。
注2:编译器提供的错误几乎无法读取,更多信息请参见 - How can I customize Scala ambiguous implicit errors when using shapeless type inequalities
3)另一种方法是讨论:
scala> addTwoThings(1)(1)
res8: String = ""
scala> addTwoThings(1)("1")
<console>:18: error: type mismatch;
found : String("1")
required: Int
addTwoThings(1)("1")
^
实验:
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
</Target>
类型推断不会查找curried参数的常见超类型(您可以阅读更多here)
答案 1 :(得分:0)
再一次,这是Scala编译器类型推断的问题
您必须提供显式类型来指导编译器
addTwoThings[String]("1",2)
以上将给出编译错误。
代码工作的原因
String和Int的常见超类型是Any。因此,Scala编译器在S
Any
scala> def addTwoThings[S](item1:S, item2:S) =
| {
| item1 + " | " + item2
| }
addTwoThings: [S](item1: S, item2: S)String
scala> println(addTwoThings("1",2))
1 | 2
scala> println(addTwoThings[String]("1",2))
<console>:22: error: type mismatch;
found : Int(2)
required: String
println(addTwoThings[String]("1",2))