假设x和y是相同类型的,并且可以是Boolean,Int,或Double.这是我想写的函数:
f(x, y) =
- if x == Boolean ==> !x
- if x == Integer or x == Double ==> x+ y
Run Code Online (Sandbox Code Playgroud)
这样做的一种方法可以是以下方法.我想知道是否有人对此有更好的想法.
def fun[T](x: T, y: T): T {
x match {
case xP: Boolean => !xP
case xP: Double => y match { case yP: Double => xP + yP }
case xP: Int => y match { case yP: Int => xP + yP }
}
}
Run Code Online (Sandbox Code Playgroud)
我不乐意这样做的原因是,x与y具有相同的类型.我不应该需要两个match-case; 对?
另外两件事:
[T <: Int, Double, Boolean] 为了将类型限制为三种类型而设置是否足够?T.Tra*_*own 11
这正是类型类旨在解决的问题.在你的情况下你可以写这样的东西:
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)
}
}
Run Code Online (Sandbox Code Playgroud)
类型值Add[X]描述了如何添加两个类型的值X.您Add[X]为每个X希望能够执行此操作的类型在范围中放置类型的隐式"实例" .在这种情况下,我提供了实例Boolean和具有实例的任何类型scala.math.Numeric(由标准库提供的类型类).如果你只是想为实例Int和Double,你可以简单地离开了numericAdd,写自己Add[Int]和Add[Double]实例.
你写fun这样的:
def fun[T: Add](x: T, y: T) = implicitly[Add[T]].apply(x, y)
Run Code Online (Sandbox Code Playgroud)
并像这样使用它:
scala> fun(true, false)
res0: Boolean = false
scala> fun(1, 2)
res1: Int = 3
scala> fun(0.01, 1.01)
res2: Double = 1.02
Run Code Online (Sandbox Code Playgroud)
这具有非常显着的优点,即在运行时不会在尚未定义操作的类型上爆炸.MatchError当您传递两个字符串时fun,不会因为异常而使程序崩溃,而是会出现一个很好的编译失败:
scala> fun("a", "b")
<console>:14: error: could not find implicit value for evidence parameter of type Add[String]
fun("a", "b")
^
Run Code Online (Sandbox Code Playgroud)
一般来说,"类型案例"匹配(即看起来像是匹配case x: X => ...)在Scala中是一个坏主意,而且几乎总有一个更好的解决方案.通常它会涉及类型类.