Как параметризировать Int как упорядоченно в scala

У меня есть класс с параметризованным типом, который я хочу использовать для операторов сравнения. Я понимаю, что для достижения этой цели мне нужно использовать свойство Ordered, но компилятор мне не нравится. Поэтому скажем, что у меня есть следующий класс:

class Test[T <: Ordered[T]] {

  def someOp(t: T) if(t < 3) ...
  ...
}

Однако, если я попытаюсь использовать этот класс следующим образом:

val test = new Test[Int]()

компилятор жалуется следующим образом:

аргументы типа [Test [Int]] не соответствуют классу Тип теста границы параметров [T <: Ordered [T]]

Может кто-нибудь объяснить мне, что я делаю неправильно здесь?

Ответы

Ответ 1

Это происходит потому, что Int не является подклассом Ordered[Int] (см. здесь).

Однако существует неявное принуждение от Int до RichInt, которое является подклассом Ordered[Int], но оно не срабатывает для нижних границ. Используйте <% (рамки просмотра) вместо который рассмотрит неявные принуждения:

class Test[T <% Ordered[T]]

Ответ 2

Вы можете использовать класс Ordering [T] как неявный параметр. Если вы хотите написать общую функцию max, она будет выглядеть так:

def max[T](a:T, b:T)(implicit ordering:Ordering[T]) = { 
  if(ordering.gt(a,b)) a else b 
}

Для примитивных типов данных, таких как Int, Float,..., в области видимости подразумевается неявное упорядочение [T], чтобы вы могли использовать это, как и следовало ожидать.

max(1,2) // gives 2

Для всех типов, которые реализуют Ordered [T], существует также неявное предоставление Ordering [T].

Существуют также различные методы в области, которые объединяют упорядочения. Например, если у вас есть N-кортеж, где у каждого элемента есть Ordering [T], автоматически существует Ordering для типа кортежа.

max((1,2), (3,4)) // gives (3,4) because 3 is larger than 1

Но если вас не устраивает какой-либо из неявно предоставленных заказов, вы можете просто написать свой собственный и передать его явно или даже получить в объеме как неявный val. Вот так:

val negativeIntOrdering = new Ordering[Int] { 
  def compare(a:Int,b:Int) = b - a 
}

max(1,2)(negativeIntOrdering) // gives 1

Таким образом, подход, основанный на стандартном стиле, гораздо более гибкий, чем подход на основе наследования. Вот почему математические библиотеки, такие как spire, широко используют его.

Одна вещь, которая не так хороша в коде выше, заключается в том, что вам нужно использовать метод lt вместо оператора. Но есть решение для этого. У заказа есть неявный метод, называемый mkOrderingOps, который предоставляет операторы для T. Вам просто нужно получить его в области, импортируя ordering._, например:

def max[T](a:T, b:T)(implicit ordering:Ordering[T]) = { 
  import ordering._; 
  if(a>b) a else b 
}