如何在Scala中数学比较两个未知类型?

时间:2019-05-30 02:29:28

标签: scala compare

我正在编写一个脚本评估器功能。它需要两个参数和一个类似这样的比较运算符:

    def compare[T,U](a:T, op:String, b:U): Boolean = {
      op match {
        case "==" => a == b
        case "<"  => a < b
        // and so on with other comparators...
      }
    }

此代码无法编译。 '<'运算符不适用于泛型类型。我无法使用'<'运算符找到数字类型的父类,因此我什至无法执行以下操作:def compare[T<:Numeric,U<:Numeric](...)

有没有办法做到这一点(或图书馆)?现在我只能测试相等/不相等。

2 个答案:

答案 0 :(得分:4)

通常,每次您想要某种类型的 interface 来对多种类型进行通用操作时,答案就是 Typeclass
在这种情况下,您可以使用scala.math.Ordering

import scala.math.Ordering
import Ordering.Implicits._

def compare[T: Ordering](a: T, op: String, b: T): Boolean = op match {
  case "==" => a == b
  case "<"  => a < b
  // and so on with other comparators...
}

现在您可以像这样使用它。

compare(10, "==", 15) //false
compare(10, "==", 10) // true
compare(10, "<", 10) // false
compare(10, "<", 11) // true

答案 1 :(得分:2)

edit:Luis的答案涉及使用单个参数类型并依赖于类型推断可能是最佳的整体解决方案。如果您设置使用两种不同的类型,则可以使用以下选项:

由于要比较两个单独的类,因此无法直接继承适合这两个类的特征成员实现。但是,如果可以提供将类转换为Double的函数文字,则可以使用以下代码。

def compare[T,U](a: T, op:String, b: U, tToDouble: T => Double, uToDouble: U => Double): Boolean = {
      op match {
        case "==" => tToDouble(a) == uToDouble(b)
        case "<"  => tToDouble(a) < uToDouble(b)
        // and so on with other comparators...
      }
    }
//example using Int
println(compare(1, "<", 2, (x:Int) => x.toDouble, (y:Int) => y.toDouble)) //true

不幸的是,我们不能使用Ordering或Numeric,因为它们是参数化的特征,期望值是用于与它们进行比较。另一种方法是接受比较器函数,该函数可以在您希望比较两种类型的对象时接受每种类型的对象。

def compare[T,U](a: T, op:String, b: U, comparator: (T,U) => Int): Boolean = {
      op match {
        case "==" => comparator(a,b) == 0
        case "<"  => comparator(a,b) < 0
        // and so on with other comparators...
      }
    }

println(compare[Int, Int](1, "<", 2, (a,b) => a-b)) //true