Scala generics: Int не соответствует Comparable? - PullRequest
5 голосов
/ 24 июля 2011

Следующие объявления Scala в порядке:

trait Base[B <: Base[B,M,ID], M <: Meta[B,M,ID], ID <: Comparable[ID]] {
    // ...
}

trait Meta[B <: Base[B,M,ID], M <: Meta[B,M,ID], ID <: Comparable[ID]] extends Ordered[Meta[_,_,_]] {
    // ...
}

trait BaseWithID[B <: BaseWithID[B,M,ID], M <: Meta[B,M,ID], ID <: Comparable[ID]] extends Base[B,M,ID] with Ordered[B] {
    // ...
}


trait BaseWithIntID[B <: BaseWithIntID[B,M,ID], M <: MetaWithIntID[B,M,ID], ID <: Comparable[ID]] extends BaseWithID[B,M,ID] {
    // ...
}

trait MetaWithIntID[B <: BaseWithIntID[B,M,ID], M <: MetaWithIntID[B,M,ID], ID <: Comparable[ID]] extends Meta[B,M,ID] {
    // ...
}

Но следующие два не являются:

trait BaseWithIntID[B <: BaseWithIntID[B,M], M <: MetaWithIntID[B,M]] extends BaseWithID[B,M,Int] {
    // ...
}

trait MetaWithIntID[B <: BaseWithIntID[B,M], M <: MetaWithIntID[B,M]] extends Meta[B,M,Int] {
    // ...
}

Разница в том, что я удалил параметр типа идентификатора в BaseWithIntID и MetaWithIntID и явно указал Int в их соответствующих базовых чертах. Но это не компилируется, значит ли это, что Int не является сопоставимым в Scala? Если это так, что я делаю не так? Я попытался заказать вместо Comparable, и это не имело значения.

Я использую Eclipse, и, как обычно, сообщения об ошибках бесполезны:

type arguments [B,M,Int] do not conform to trait BaseWithID's type parameter bounds [B <: BaseWithID[B,M,ID],M <: Meta[B,M,ID],ID <: java.lang.Comparable[ID]]

Это просто говорит о том, что что-то не так, но не то, какой параметр типа неверен и почему. Глядя на этот вопрос , я подумал, что мог бы вместо этого попробовать «ID <% Comparable [ID]», но это недопустимо в объявлении черты. </p>

На самом деле, это тоже не работает (с тем же сообщением об ошибке):

trait TestBase extends BaseWithID[TestBase,TestMeta,Int]

trait TestMeta extends Meta[TestBase,TestMeta,Int]

Ответы [ 2 ]

9 голосов
/ 24 июля 2011

Int действительно не сравним в scala, конечно, потому что он фактически реализован как java int, а не java.lang.Integer.Я не уверен, что это было бы невозможно, C # struct (типы значений) может реализовывать интерфейсы, но здесь это не сделано.

Обычно вы говорите, что для вашего типа идентификатора есть Ordering, доступный в неявном объеме, с ID : Ordering.

На простом примере:

import Ordering.Implicits._
def max[A : Ordering](x: A, y: A) : A = if (x > y) then x else y

Это равносильно передаче Ordering (что аналогично java.util.Comparator) функции.Действительно, объявление

def max[A : Ordering](x: A, y: A)

переводится в

def max[A](x: A, y: A)(implicit ev: Ordering[A])

, где ev - новое имя.Если порядок A: Ordering появляется в классе, а не в определении метода, как в вашем коде, он преобразуется в неявный параметр конструктора, который будет сохраняться в поле, если это необходимо, и будет доступен в неявной области видимости в классе.Это более гибко, чем заставлять A быть Comparable (Ordered в scala), так как оно может использоваться в классе, который не принадлежит вам и не реализовал Comparable.Вы также можете выбирать между разными Odering в одном и том же классе, хотя бы только путем изменения значения по умолчанию: есть метод def reverse : Ordering в Ordering, который делает именно это.

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

Типы, которые реализуют Comparable<T> в Java, автоматически получают Ordering в неявной области действия в силу неявного метода (ordered) в объекте Ordering.Java Comparator<T> также может быть преобразован в Ordering (Ordering.comparatorToOrdering).

, импортирующий Ordering.Implicits._, позволяет вам использовать хороший синтаксис x > y, когда Ordering[A] находится в неявной области видимости.,

0 голосов
/ 24 июля 2011

Ответ на вопрос «Означает ли это, что Int не является сопоставимым в Scala?»очевидно, ДА, потому что если я заменю Int на java.lang.Integer, то он компилируется без ошибок.Проблема в том, что мне приходится создавать объект-оболочку каждый раз, когда я получаю доступ к идентификатору, что случается часто и, следовательно, обходится дорого.

Я хотел указать, что идентификатор сопоставим / упорядочентак что я мог бы упорядочить сам BaseWithID и явно определить в нем метод сравнения, используя сопоставимые идентификаторы.

Решение, на данный момент, похоже, состоит в том, чтобы не указывать, что идентификатор упорядочен, и позволитьконкретный класс реализует сравнение себя, вместо того, чтобы реализовывать его один раз в этой черте.У кого-нибудь есть лучшее решение?

...