Scala 泛型:Int 不符合 Comparable?
以下 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]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Int 在 scala 中确实无法比较,当然是因为它实际上是作为 java
int
实现的,而不是java.lang.Integer
。我不确定这是不可能的,C# struct(值类型)可以实现接口,但这里没有这样做。您通常所做的就是说,在您的 ID 类型的隐式范围内有一个可用的
Ordering
,其中ID : Ordering
。举一个简单的例子:
这相当于将一个 Ordering(与 java.util.Comparator 相同)传递给函数。事实上,该声明
翻译为
ev
是一个新名称。如果 A : Ordering 出现在类上而不是方法定义上(如代码中所示),它会转换为构造函数的隐式参数,如果需要,该参数将保留在字段中,并可在类的隐式作用域中使用。这比强制 A 为Comparable
(在 scala 中为Ordered
)更灵活,因为它可能用在不属于您的且未实现 Comparable 的类上。您也可以在同一类上的不同 Odering 之间进行选择,只要通过反转默认的 Odering 即可:Ordering
上有一个defverse : Ordering
方法,它就是这样做的。不利的一面是,虚拟机不太可能能够内联对比较方法的调用,但对于泛型中的接口方法来说也不太可能。
在 Java 中实现 Comparable 的类型会凭借对象
ordered
) 自动在隐式作用域中获取Ordering
>订购。 javaComparator
也可以转换为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
, notjava.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, withID : Ordering
.On a simple example:
This amounts to passing an Ordering (which is the same thing as a
java.util.Comparator
) to the function. Indeed, the declarationtranslates to
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 beComparable
(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 adef reverse : Ordering
method onOrdering
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 anOrdering
in implicit scope by virtue of an implicit method (ordered
) in objectOrdering
. A javaComparator<T>
can also be converted to anOrdering
(Ordering.comparatorToOrdering
).importing Ordering.Implicits._ allows you the nice
x > y
syntax, when anOrdering[A]
is in implicit scope.“这是否意味着 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?