【问题标题】:The intersection of Java generics and Scala is...not going wellJava 泛型和 Scala 的交集……进展不顺利
【发布时间】:2019-08-26 14:40:38
【问题描述】:

我坦率地承认在这里有点超出我的深度。我在类型系统方面的正式培训比我晚了几十年。我在 Java 中使用过泛型一两次,但我不能声称对它们有深刻而透彻的理解。我也是 Scala 的新手,所以我也没有声称对它的类型系统有深刻或透彻的了解。

我开始更新我的 XML Calabash v2 实现,它是用 Scala(今天的 2.12)编写的,以使用 Saxon 9.9。 Saxon 9.9 在许多地方引入了泛型。我没意见。我想我可以应付。

不过,我显然不能。

绊脚石是试图实现一个扩展 ExtensionFunctionDefinition 类的类。它有一个扩展 ExtensionFunctionCall 类的内部类。反过来,它有一个抽象方法 call,在 Java 中如此定义:

public abstract Sequence<?> call(
    XPathContext context,
    Sequence[] arguments
)

我第一次尝试在 Scala 中定义它是:

override def call(
    context: XPathContext,
    arguments: Array[Sequence]
): Sequence[_]

但这不能编译:“trait Sequence 接受类型参数”。

这是真的:

public interface Sequence<T extends Item<?>>

(项目,顺便说一句,是:

public interface Item<T extends Item<?>>
extends GroundedValue<T>

由于其他原因,我觉得有点令人困惑)

对于我的第二次尝试,我尝试了:

override def call(
    context: XPathContext,
    arguments: Array[Sequence[_]]
): Sequence[_]

但是,有人告诉我,这不会覆盖任何东西。听着,编译器说:

[error] (Note that Array[net.sf.saxon.om.Sequence]
does not match Array[net.sf.saxon.om.Sequence[_]]:
their type parameters differ)

我们似乎陷入了僵局。当然,我可以在 Java 中实现该死的东西,但这是 Scala 的实际限制还是我的理解?

顺便说一句,关于我的第一次尝试,我之前一直在撒谎。我的第一次尝试实际上是:

override def call(
    context: XPathContext,
    arguments: Array[Sequence[_ <: Item[_ <: Item[_]]]]
): Sequence[_ <: Item[_ <: Item[_]]]

我通过直接将 Java 复制到 Scala 并让 IntelliJ IDEA 翻译它来制作。我没有弄清楚如何处理 Item 声明的递归性质。

【问题讨论】:

  • 另一个关于raw types 的问题目前在热门问题中。多么奇怪的巧合。

标签: java scala generics


【解决方案1】:

试试

override def call(context: XPathContext, arguments: Array[Sequence[_ <: Item[_]]]): Sequence[_] = ???

【讨论】:

  • 不成功:(注意 Array[net.sf.saxon.om.Sequence[]] 不匹配 Array[net.sf.saxon.om.Sequence[ <: net.sf.saxon.om.item>
  • @Norm 在某种意义上它们确实匹配。你可以检查 implicitly[Array[Sequence[_ &lt;: Item[_]]] =:= Array[Sequence[_]]] implicitly[Array[Sequence[_]] =:= Array[Sequence[_ &lt;: Item[_]]]] 编译。
【解决方案2】:

我认为在 java 中没有类型参数的Sequence 会转换为Sequence[Foo],其中Foo 是可能的最高超类型(在这种情况下为Item)。 所以,我希望这样的事情能够奏效:

override def call(context: XPathContext, arguments: Array[Sequence[Item[_]]]): Sequence[_] = ???

【讨论】:

  • 不,这不会编译:Error:(6, 14) method call overrides nothing. Note: the super classes of object App contain the following, non final members named call: def call(x$1: com.sun.org.apache.xpath.internal.XPathContext,x$2: Array[App_1.Sequence]): App_1.Sequence[_] override def call(context: XPathContext, arguments: Array[Sequence[Item[_]]]): Sequence[_] = ???.
  • 是的,这个似乎没有覆盖 call 的任何一个定义。
【解决方案3】:

这里肯定可以编译(从而确认 Dmytro Mitin 的提议有效):

// ExtensionFunctionCall.java
public interface ExtensionFunctionCall {
  Sequence<?> call(String ctx, Sequence[] args);
}

// Item.java
public interface Item<T extends Item<?>> {}

// Sequence.java
public interface Sequence<T extends Item<?>> {}

// Impl.scala
class Impl extends ExtensionFunctionCall {
  override def call(
    ctx: String,
    args: Array[Sequence[_ <: Item[_]]]
  ): Sequence[_] = ???
}

顺便说一句,这不仅仅是 Scala 的问题。如果您暂时忘记了 Scala,并尝试在 Java 中实现它,您将得到基本相同的错误:

class ImplJava implements ExtensionFunctionCall {
  public Sequence<?> call(
    String ctx,
    Sequence<?>[] args
  ) {
    return null;
  }
}

给予:

ImplJava.java:1: error: ImplJava is not abstract and does not override abstract method call(String,Sequence[]) in ExtensionFunctionCall
class ImplJava implements ExtensionFunctionCall {
^
ImplJava.java:2: error: name clash: call(String,Sequence<?>[]) in ImplJava and call(String,Sequence[]) in ExtensionFunctionCall have the same erasure, yet neither overrides the other
  public Sequence<?> call(
                     ^
2 errors

现在,这真是令人费解,我不知道如何在 Java 中写下这种类型。我不确定它是否可以在不恢复到 1.4 风格的情况下在 Java 中表达。 Sequence[] 是邪恶的,或者引用 this wonderful article linked by Dmytro Mitin:

原始类型不好。停止使用它们

【讨论】:

  • 对于上下文,这在我的上下文中的 Java 中运行良好:public Sequence> call(XPathContext context, Sequence[] arguments)
  • @Norm 我的问题是似乎有两个独立的概念:Sequence 和 Sequence&lt;?&gt;,它们完全不兼容,不能相互互换,并且都以某种奇怪的方式映射到 Scala 的存在类型大大地。我什至不知道有 两个 类型的 Java 类型都映射到 Scala 的存在。我确信在 Java 1.4 之后,旧的擦除泛型变成了可以通过通配符表达的东西的语法糖,但显然情况并非如此。
  • 很公平。感谢您提供非常方便的链接。尽管我已经传递了链接,但我无法控制 Java 库。与此同时,我编写了一些 Java shim 代码。
  • @AndreyTyukin 您并非总是可以避免使用原始类型。例如,因为 Java 中没有 Scala 中的高级类型 stackoverflow.com/questions/55528032/…
猜你喜欢
  • 1970-01-01
  • 2014-01-13
  • 1970-01-01
  • 2021-06-22
  • 1970-01-01
  • 2012-05-21
  • 2021-12-13
  • 1970-01-01
  • 2017-12-24
相关资源
最近更新 更多