这正是类型类旨在解决的问题。在你的情况下,你可以写这样的东西:
trait Add[A] {
def apply(a: A, b: A): A
}
object Add {
implicit val booleanAdd: Add[Boolean] = new Add[Boolean] {
def apply(a: Boolean, b: Boolean): Boolean = !a
}
implicit def numericAdd[A: Numeric]: Add[A] = new Add[A] {
def apply(a: A, b: A): A = implicitly[Numeric[A]].plus(a, b)
}
}
类型的值Add[X]
描述如何将两个类型的值相加X
。您放置类型的隐式“实例”Add[X]
适用于每种类型X
您希望能够对其执行此操作。在这种情况下,我提供了实例Boolean
以及任何具有以下实例的类型scala.math.Numeric
(标准库提供的类型类)。如果您只想要实例Int
and Double
,你可以简单地省略numericAdd
并写你自己的Add[Int]
and Add[Double]
实例。
你会写你的fun
像这样:
def fun[T: Add](x: T, y: T) = implicitly[Add[T]].apply(x, y)
并像这样使用它:
scala> fun(true, false)
res0: Boolean = false
scala> fun(1, 2)
res1: Int = 3
scala> fun(0.01, 1.01)
res2: Double = 1.02
这具有非常显着的优点,即不会在运行时对尚未定义操作的类型造成破坏。而不是用MatchError
当你通过时例外,例如两个字符串到fun
,你会得到一个很好的编译失败:
scala> fun("a", "b")
<console>:14: error: could not find implicit value for evidence parameter of type Add[String]
fun("a", "b")
^
一般来说,“类型大小写”匹配(即看起来像的匹配case x: X => ...
)在 Scala 中是一个坏主意,而且几乎总是有更好的解决方案。通常它会涉及类型类。