在Scala中实现具有原始类型的方法

7

我希望您能帮忙翻译一下关于IT技术的文章,涉及到Drools Planner(Java编写)在Scala中使用时遇到的问题。Drools Planner中的一个接口声明如下:

public interface Score<S extends Score> extends Comparable<S>

然而,另一个接口使用“Score”作为原始类型:

public interface Solution {
    Score getScore();

接下来我想在Scala中实现这个接口:

class MySolution extends Solution {
    def getScore: Score = ...

我遇到了编译错误:Scala 编译器不允许仅写 'def getScore: Score'。当我尝试添加 'Score[_]' 或 'Score[whatever]' 时,编译器会报类型不兼容的错误。我该怎么办?


你能否也发布类型兼容性错误的完整文本? - Kevin Wright
有趣的案例。Adam Warski也在用户邮件列表上发布了类似的问题。我们应该在Drools Planner源代码中修复这个问题。我创建了这个问题来跟踪它:https://issues.jboss.org/browse/JBRULES-2924 - Geoffrey De Smet
1
谢谢。不过我也希望Scala在这方面能够提供一些支持。Drools Planner可能不是唯一存在这个问题的库。 - iirekm
Drools Planner的开发人员应该修复他们的代码。相关例子是,即使Sun/Oracle也会做一些愚蠢的事情:http://lampsvn.epfl.ch/trac/scala/ticket/3634 - soc
4个回答

9

编写一个Java类,作为Java接口所需和Scala允许之间的桥梁。

SolutionBridge.java:

abstract class SolutionBridge implements Solution {
    public Score getScore() {
        return scalaGetScore();
    }

    abstract Score<?> scalaGetScore();
}

SolutionScala.scala:

class SolutionScala extends SolutionBridge {
    def scalaGetScore() = null.asInstanceOf[Score[_]]
}

是的,我有一个类似的想法,但需要用Java实现。我更喜欢直接使用Scala实现。 - iirekm
@iirekm 是的,好吧,没这么幸运。请注意,原始类型属于 Java 版本,它在最后一个已终止支持的版本之前。Java 1.4 不在 Scala 支持的 JVM 版本之列。 - Daniel C. Sobral

4

你省略的错误信息并非无关紧要。关于“我还希望Scala能提供一些支持”,你可以通过阅读错误信息参与进程,如果你不能理解它们,在提问时请包含错误信息,而不是模糊地转述它们。

错误信息很重要,即使它们令人困惑,特别是令人困惑的情况下。

以下是2.8.1版本中的错误信息:

a.scala:2: error: overriding method getScore in trait Solution of type ()Score[_ <: Score];
 method getScore has incompatible type
  def getScore: Score[_] = null
      ^
one error found

这是trunk的错误:

a.scala:2: error: overriding method getScore in trait Solution of type ()Score[_ <: AnyRef];
 method getScore has incompatible type
  def getScore: Score[_] = null
      ^
one error found

这里有一个关键区别,这解释了为什么当我按照错误信息的指示操作时它能够在主干版本上运行。

// this compiles with 2.9, but not with 2.8
class MySolution extends Solution {
  def getScore: Score[_ <: AnyRef] = null
}

在Java源代码中,原始类型Score的使用方式(在一个位置作为类型构造函数,但在另一个位置隐含地存在着存在类型参数,并将第二个出现限制于第一个)让人感到惊讶,它竟然能够正常工作。你不想知道这种事情已经对编译器造成了多大的破坏。虽然使用原始类型会很方便,但是有些事情是不可能的,有些事情是不可取的,还有一些事情需要太多人的努力来保持船只的浮动。原始类型获得三冠军。


这种损害被称为向后兼容性。是的,这并不容易,但为了更广泛地采用Scala是必要的。 - iirekm
甚至Java也无法提供您所需的那种高度向后兼容性。Sun/Oracle宣布在未来的Java版本中可能会停止支持原始类型。Scala并不是为了重复Java所犯的所有错误而构建的。 - soc

3
Drools Planner的下一个版本(5.2.0.M2)将修复此问题这是git上的提交记录。 在某些情况下,人们想要定义自己的Score实现(例如NurseRosterScore实现HardAndSoftScore),以便能够向用户显示每个硬性或软性约束类型中最佳解决方案违反了什么。这个改变是使它更容易和更清晰的第一步(虽然这已经是可能的)。

非常感谢。我会在空闲时间尝试一下。 - iirekm

0

你尝试过将 Score 进行强制类型转换吗?

val s = solution.getScore.asInstanceOf[Score[Int]]

这不是问题:我还没有一个“solution”对象。当我尝试实现“MySolution extends Solution”时,就会出现这个问题。 - iirekm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接