сигнатуры scala полиморфного типа с помощью Ordering и ClassTag - PullRequest
0 голосов
/ 25 апреля 2018

Мне нужна помощь в понимании этой сигнатуры типа:

def func[A : Ordering : ClassTag](a: A) = ???

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

Эти два кажутся похожими:

import scala.reflect.ClassTag

// type signature in question
def func1[A : Ordering : ClassTag](elems: A*) = 
  Array[A](elems: _*).sorted

// my typical type signature
def func2[A <% Ordered[A]](elems: A*)(implicit c: ClassTag[A]) = 
  Array[A](elems: _*).sorted

Пример использования:

class BB(val i: Int) extends Ordered[BB] {
  def compare(that: BB): Int = that.i - i
  override def toString = s"BB(${i})"
}

func1(new BB(33), new BB(100), new BB(-1))
func2(new BB(33), new BB(100), new BB(-1))

Вывод для каждого из них:

Array[BB] = Array(BB(100), BB(33), BB(-1))

Один крайний случай, который я могу придумать, где они различаются ... указывает на то, что один не просто синтаксический сахардля другого ... это следующее, где функция имеет неявный порядок для класса, который отличается от естественного порядка сортировки класса.

Этот пример (ниже) работает нормально, а implicit val ordering переопределяет класс BBестественный порядок сортировки, как я (вроде) ожидал.

def func3[A <% Ordered[A] : ClassTag](elems: A*) = {
  // opposite order defined in class BB
  implicit val ordering: Ordering[A] = 
    Ordering.by{ case bb: BB => bb.i }  

  Array[A](elems: _*).sorted
}

Эта версия (ниже) дает мне ошибку ...

def func3[A : Ordering : ClassTag](elems: A*) = {
  // opposite order defined in class BB
  implicit val ordering: Ordering[A] = 
    Ordering.by{ case bb: BB => bb.i }  

  Array[A](elems: _*).sorted
}

ошибка: неоднозначные неявные значения:оба значения доказательства $ 1 типа Ordering [A] и valупорядочение типа Ordering [A] соответствует ожидаемому типу scala.math.Ordering [A]

Итак, основываясь на этом ... Я предполагаю, что : Ordering преобразует Ordered[BB] вimplicit val ordering ... или что-то в этом роде?Существуют ли более глубокие различия, которые не могут быть обнаружены в моих примерах игрушек?

Заранее спасибо.

1 Ответ

0 голосов
/ 25 апреля 2018

A : после параметра типа является синтаксическим сахаром для объявления неявных параметров.В этом случае это означает, что

def func1[A: Ordering: ClassTag](elems: A*) = Array[A](elems: _*).sorted

совпадает с

def func1[A](elems: A*)(implicit ordering: Ordering[A], classTag: ClassTag[A]) = Array[A](elems: _*).sorted

С другой стороны, func2 объявляет границу вида (<%) от A доOrdered.Зная это, компилятор может вызвать Ordering[Ordered], который передается методу sorted

Причина, по которой последняя версия fun3 не компилируется, заключается в том, что вы предоставляете 2 неявных Ordering[A] вscope: тот, который объявлен как неявный параметр fun3, а неявный val ordering.Компилятор не знает, какой из них выбрать, и он жалуется на это, вы должны удалить один из них, чтобы это исправить.

Во всяком случае, не стоит вводить код для конкретных типов в реализации этих функций.Это сопоставление с образцом при создании val ordering завершится неудачей для любого типа, который не является BB.

Если ваша цель - определить конкретный Ordering[BB], вы можете сделать это в сопутствующем объекте BB, а затем загрузить его в неявную область действия вызывающей функции, например:

class BB(val i: Int) {
  override def toString: String = s"BB(${i})"
}

object BB {
  implicit val ordering = Ordering.by[BB, Int](_.i)
  val reverseOrdering = Ordering.by[BB, Int](-_.i)
}

Затем, когда вы попытаетесь заказать BB, он выберет неявный порядок по умолчанию, но вы всегда можете перезаписать его, выполнив

implicit val ord = BB.reverseOrdering
Seq[BB]().sorted
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...