Как я могу математически сравнить два неизвестных типа в Scala? - PullRequest
2 голосов
/ 30 мая 2019

Я пишу небольшую функцию оценки сценариев. Требуется два аргумента и оператор сравнения, подобный этому:

    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...
      }
    }

Этот код не скомпилируется. Оператор «<» не работает с общими типами. Я не смог найти родительский класс для числовых типов с помощью оператора «<», поэтому я даже не могу сделать что-то вроде: <code>def compare[T<:Numeric,U<:Numeric](...)

Есть ли способ сделать это (или библиотеку)? Прямо сейчас я могу проверять только равные / не равные.

Ответы [ 2 ]

4 голосов
/ 30 мая 2019

В общем, всякий раз, когда вам нужен какой-то интерфейс для общих операций над несколькими типами, ответом будет Класс типов .
В этом конкретном случае вы можете использовать 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
2 голосов
/ 30 мая 2019

edit: ответ Луиса, включающий использование одного типа параметра и опору на вывод типа, вероятно, является наилучшим общим решением. Если вы используете два отдельных типа, вот несколько вариантов:

Поскольку вы пытаетесь сравнить два отдельных класса, вы не можете напрямую наследовать реализацию члена-признака, которая будет соответствовать обоим. Однако, если вы можете предоставить функциональные литералы, которые преобразуют класс в 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

К сожалению, мы не можем использовать Упорядочивание или Числовое, потому что это параметризованные черты и ожидание для сравнения с самим собой. Другой метод - просто принять функцию компаратора, которая принимает объекты каждого типа всякий раз, когда вы хотите сравнить два типа объектов.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...