Scala 泛型:Int 不符合 Comparable?

发布于 2024-11-26 03:27:44 字数 1764 浏览 0 评论 0 原文

以下 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 中的 ID 类型参数,并在各自的基本特征中显式指定了 Int。但这不能编译,那么这是否意味着 Int 在 Scala 中不可比较?如果是的话,我做错了什么?我尝试使用 Ordered 而不是 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]”,但这在特征声明中是不合法的。

实际上,这也不起作用(具有相同的错误消息):

trait TestBase extends BaseWithID[TestBase,TestMeta,Int]

trait TestMeta extends Meta[TestBase,TestMeta,Int]

The following Scala declarations are OK:

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] {
    // ...
}

But the following two are not:

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] {
    // ...
}

The difference is that I removed the ID type parameter in BaseWithIntID and MetaWithIntID, and specified Int explicitly in their respective base traits. But this does not compile, so does that mean that Int is not Comparable in Scala? If it is, what am I doing wrong? I tried Ordered instead of Comparable, and it made not difference.

I'm using Eclipse, and as usual, the error messages are unhelpful:

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]]

It just says that something is wrong, but not which type parameter is wrong, and why. Looking at this question, I thought I could try "ID <% Comparable[ID]" instead, but that is not legal in a trait declaration.

Actually, this does not work either (with the same error message):

trait TestBase extends BaseWithID[TestBase,TestMeta,Int]

trait TestMeta extends Meta[TestBase,TestMeta,Int]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜光 2024-12-03 03:27:44

Int 在 scala 中确实无法比较,当然是因为它实际上是作为 java int 实现的,而不是 java.lang.Integer 。我不确定这是不可能的,C# struct(值类型)可以实现接口,但这里没有这样做。

您通常所做的就是说,在您的 ID 类型的隐式范围内有一个可用的 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 (在 scala 中为 Ordered)更灵活,因为它可能用在不属于您的且未实现 Comparable 的类上。您也可以在同一类上的不同 Odering 之间进行选择,只要通过反转默认的 Odering 即可:Ordering 上有一个 defverse : Ordering 方法,它就是这样做的。

不利的一面是,虚拟机不太可能能够内联对比较方法的调用,但对于泛型中的接口方法来说也不太可能。

在 Java 中实现 Comparable 的类型会凭借对象 ordered) 自动在隐式作用域中获取 Ordering >订购。 java Comparator 也可以转换为 Ordering (Ordering.comparatorToOrdering)。

导入 Ordering.Implicits._ 可以让你得到很好的 x >; y 语法,当 Ordering[A] 位于隐式作用域中时。

Int is indeed not comparable in scala, certainly because it is in fact implemented as java int, not java.lang.Integer. I'm not sure that would have been impossible, C# struct (value types) may implement interfaces, but this is not done here.

What you usually do is say that there is an Ordering available in implicit scope for your ID type, with ID : Ordering.

On a simple example:

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

This amounts to passing an Ordering (which is the same thing as a java.util.Comparator) to the function. Indeed, the declaration

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

translates to

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

where ev is a fresh name. If A : Ordering appears on class rather than method definition, as in your code, it translates to an implicit parameter to the constructor, that will be kept in a field if needed, and be available in implicit scope in the class. This is more flexible than forcing A to be Comparable (Ordered in scala) as it may be used on a class that is not yours and has not implemented Comparable. You can choose between different Odering on the same class too, if only by reversing the default one: there is a def reverse : Ordering method on Ordering which does just that.

On the bad side, it is not likely the VM will be able to inline the call to the comparison method, but it was not likely either with an interface method in a generic.

Types which implement Comparable<T> in java automatically get an Ordering in implicit scope by virtue of an implicit method (ordered) in object Ordering. A java Comparator<T> can also be converted to an Ordering (Ordering.comparatorToOrdering).

importing Ordering.Implicits._ allows you the nice x > y syntax, when an Ordering[A] is in implicit scope.

逆流 2024-12-03 03:27:44

“这是否意味着 Int 在 Scala 中不可比较?”的答案显然是 YES,因为如果我用 java.lang.Integer 替换 Int,那么它编译时不会出错。问题是,每次访问 ID 时,我最终都必须创建一个包装对象,这种情况经常发生,因此成本高昂。

我想指定 ID 是可比较/有序的,以便我可以使 BaseWithID 本身有序,并使用可比较的 ID 在其中显式定义比较方法。

目前的解决方案似乎是不指定 ID 是有序的,并让具体类实现自身进行比较,而不是在特征中一次性实现它。有人有更好的解决方案吗?

The answer to "Does that mean that Int is not Comparable in Scala?" is obviously YES, because if I replace Int with java.lang.Integer, then it compiles without error. The problem is then, that I end up having to create a wrapper object every time that I access the ID, which is going to happen often and therefore be expensive.

I wanted to specify that ID is Comparable/Ordered so that I could make the BaseWithID itself ordered, and define the compare method explicitly in it by using the comparable IDs.

The solution, at the moment, seems to be to not specify that ID is ordered, and let the concrete class implement compare itself, instead of implementing it a single time in the trait. Has anyone got a better solution?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文