Java泛型和Scala的交集......不太顺利。

4
我承认在这方面我有点力不从心。我接受过类型系统的正式培训,但那已经是几十年前的事情了。我曾经在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 takes type parameters”。

这是正确的:

public interface Sequence<T extends Item<?>>

(顺便说一下,"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声明的递归性质。然而,这种方法并没有成功。


另一个关于原始类型的问题目前正在热门问题中。真是个奇怪的巧合。 - Andrey Tyukin
3个回答

3

尝试

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
@Norm,它可以编译。https://gist.github.com/DmytroMitin/7d7e67274061f90572d63672e67e09e6 - Dmytro Mitin
在某种意义上它们是匹配的。你可以检查 implicitly[Array[Sequence[_ <: Item[_]]] =:= Array[Sequence[_]]]implicitly[Array[Sequence[_]] =:= Array[Sequence[_ <: Item[_]]]] 程序编译通过。 - Dmytro Mitin

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中编写此类型。我不确定是否可以在Java中表达它,而不回到1.4风格。 Sequence [] 的东西只是邪恶的,或者引用Dmytro Mitin链接的这篇美妙的文章所说的:

裸类型很糟糕,请停止使用。


在我的环境中,这段代码在Java中运行良好:public Sequence<?> call(XPathContext context, Sequence[] arguments) - Norm
2
@Norm 我的问题在于有两个看似不同的概念:SequenceSequence<?>,它们完全不兼容,也不能互相替换,并且在某种奇怪的方式下都被映射到了 Scala 的存在类型。我甚至没有意识到有 两个 Java 类型族都被映射到了 Scala 的存在类型上。我确信在Java 1.4之后,旧的泛型已经成为了仅仅是通配符表达式的语法糖,但事实并非如此。 - Andrey Tyukin
好的,非常感谢提供这个非常有用的链接。虽然我无法控制Java库,但我已经将链接传递给了相关人员。同时,我编写了一些Java shim代码。 - Norm
@AndreyTyukin 你并不总是能避免使用原始类型。例如,由于 Scala 中缺少 Java 中的高级类型,因此可能需要使用原始类型。https://stackoverflow.com/questions/55528032/how-to-export-scala-transformation-to-java/ - Dmytro Mitin

0

我认为在Java中没有类型参数的Sequence会被翻译成Sequence[Foo],其中Foo是最高可能的超类型(在这种情况下是Item)。 因此,我期望像这样的代码可以正常工作:

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

不,这个无法编译:错误:(6,14)方法调用未覆盖任何内容。 注意:对象App的超类包含以下非最终成员名为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[_] = ???。 - Dmytro Mitin
是的,这个似乎没有覆盖 call 的任何定义。 - Norm

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