编译错误:在Scala中使用Java类的有界通配符问题

huangapple go评论85阅读模式
英文:

Compilation error with bounded wildcards using Java classes in Scala

问题

在Java中,我们定义了一个名为ObservableCollection.java的类,如下所示:

public class ObservableCollection<T> implements Collection<T> {

   public SubscriptionHandle onElementAdded(Consumer<T> onAdded) {
     // ... 
   }
}

还有一个返回ObservableCollectionAgentService.java

public interface AgentService {

    ObservableCollection<? extends Agent> getAgents();

}

现在,我想在Scala项目中使用这个ObservableCollection.java,代码如下:

def test(service: AgentService): Unit = {
  val onAdded: Consumer[_ <: Agent] = ???
  service.getAgents.onElementAdded(onAdded)
}

尝试这样做会导致以下编译错误:

type mismatch;
 found   : java.util.function.Consumer[_$1] where type _$1 <: com.xxxx.xx.xx.agent.Agent
 required: java.util.function.Consumer[?0] where type ?0 <: com.xxxx.xx.xx.agent.Agent
    service.getAgents.onElementAdded(onAdded)
                                     ^
one error found

这对我来说不太有意义。有没有方法可以让这个运行起来?

编辑: 使用Consumer[Agent]会导致以下错误:

type mismatch;
 found   : java.util.function.Consumer[com.xxxx.xx.xx.agent.Agent]
 required: java.util.function.Consumer[?0] where type ?0 <: com.kuka.cc.si.agent.Agent
Note: com.xxxx.xx.xx.agent.Agent >: ?0, but Java-defined trait Consumer is invariant in type T.
You may wish to investigate a wildcard type such as `_ >: ?0`. (SLS 3.2.10)
    service.getAgents.onElementAdded(onAdded)
                                     ^
one error found
英文:

In Java, we have defined an ObservableCollection.java like this:

public class ObservableCollection&lt;T&gt; implements Collection&lt;T&gt; {

   public SubscriptionHandle onElementAdded(Consumer&lt;T&gt; onAdded) {
     // ... 
   }
}

And an AgentService.java that returns an ObservableCollection:

public interface AgentService {

    ObservableCollection&lt;? extends Agent&gt; getAgents();

}

Now, I am trying to use this ObservableCollection.java in a Scala project like this:

  def test(service: AgentService): Unit = {
    val onAdded: Consumer[_ &lt;: Agent] = ???
    service.getAgents.onElementAdded(onAdded)
  }

Trying this results in the following compilation error:

type mismatch;
 found   : java.util.function.Consumer[_$1] where type _$1 &lt;: com.xxxx.xx.xx.agent.Agent
 required: java.util.function.Consumer[?0] where type ?0 &lt;: com.xxxx.xx.xx.agent.Agent
    service.getAgents.onElementAdded(onAdded)
                                     ^
one error found

This does not make much sense to me. Is there a way I can get this running?

Edit: Using a Cosumer[Agent] results in the following error:

type mismatch;
 found   : java.util.function.Consumer[com.xxxx.xx.xx.agent.Agent]
 required: java.util.function.Consumer[?0] where type ?0 &lt;: com.kuka.cc.si.agent.Agent
Note: com.xxxx.xx.xx.agent.Agent &gt;: ?0, but Java-defined trait Consumer is invariant in type T.
You may wish to investigate a wildcard type such as `_ &gt;: ?0`. (SLS 3.2.10)
    service.getAgents.onElementAdded(onAdded)
                                     ^
one error found

答案1

得分: 2

以下是翻译好的内容:

首先是关于 Scala-Java 互操作性的内容:

不在于 Scala-Java 互操作性以下 Scala 代码也无法编译

import java.util.function.Consumer
import java.util

trait Agent
trait SubscriptionHandle
trait AgentService {
  def getAgents: ObservableCollection[_ <: Agent]
}
trait ObservableCollection[T] extends util.Collection[T] {
  def onElementAdded(onAdded: Consumer[T]): SubscriptionHandle
}

def test(service: AgentService): Unit = {
  val onAdded: Consumer[_ <: Agent] = ???
  val agents: ObservableCollection[_ <: Agent] = service.getAgents
  agents.onElementAdded(onAdded)
}
// 类型不匹配;
// 找到:java.util.function.Consumer[_$2],其中类型 _$2 <: App.Agent
// 需要:java.util.function.Consumer[_$3]

你错误地使用了存在类型(通配符泛型)。以下代码无法编译:

trait X[T]
trait Y[T] {
  def foo(x: X[T]) = ???
}
val x: X[_] = ???
val y: Y[_] = ???
y.foo(x) // 无法编译

xy 都具有存在类型,但 foo 接受类型为 X[T]x,其中 T 必须与 y 的类型中的 T 相同,即 Y[T],因此无法保证 T 相同。

修复编译错误的一种方法是为 AgentService 添加泛型:

trait Agent
trait SubscriptionHandle
trait AgentService[T <: Agent] {
  def getAgents: ObservableCollection[T]
}
trait ObservableCollection[T] extends util.Collection[T] {
  def onElementAdded(onAdded: Consumer[T]): SubscriptionHandle
}

def test[T <: Agent](service: AgentService[T]): Unit = {
  val onAdded: Consumer[T] = ???
  val agents: ObservableCollection[T] = service.getAgents
  agents.onElementAdded(onAdded)
}

或者将泛型添加到其方法中:

trait Agent
trait SubscriptionHandle
trait AgentService {
  def getAgents[T <: Agent]: ObservableCollection[T]
}
trait ObservableCollection[T] extends util.Collection[T] {
  def onElementAdded(onAdded: Consumer[T]): SubscriptionHandle
}

def test[T <: Agent](service: AgentService): Unit = {
  val onAdded: Consumer[T] = ???
  val agents: ObservableCollection[T] = service.getAgents
  agents.onElementAdded(onAdded)
}
英文:

The thing is not in Scala-Java interop. The following Scala code doesn't compile either

import java.util.function.Consumer
import java.util

trait Agent
trait SubscriptionHandle
trait AgentService {
  def getAgents: ObservableCollection[_ &lt;: Agent]
}
trait ObservableCollection[T] extends util.Collection[T] {
  def onElementAdded(onAdded: Consumer[T]): SubscriptionHandle
}

def test(service: AgentService): Unit = {
  val onAdded: Consumer[_ &lt;: Agent] = ???
  val agents: ObservableCollection[_ &lt;: Agent] = service.getAgents
  agents.onElementAdded(onAdded)
//                      ^^^^^^^
}

//type mismatch;
// found   : java.util.function.Consumer[_$2] where type _$2 &lt;: App.Agent
// required: java.util.function.Consumer[_$3]

You misuse existential types (wildcard generics). The following code can't compile

trait X[T]
trait Y[T] {
  def foo(x: X[T]) = ???
}
val x: X[_] = ???
val y: Y[_] = ???
y.foo(x) // doesn&#39;t compile

Both x and y have existential types but foo accepts x of type X[T], where T must be the same as T in the type of y, i.e. Y[T], so you can't guarantee that T are the same.

One way to fix compilation is to add generics to AgentService

trait Agent
trait SubscriptionHandle
trait AgentService[T &lt;: Agent] {
  def getAgents: ObservableCollection[T]
}
trait ObservableCollection[T] extends util.Collection[T] {
  def onElementAdded(onAdded: Consumer[T]): SubscriptionHandle
}

def test[T &lt;: Agent](service: AgentService[T]): Unit = {
  val onAdded: Consumer[T] = ???
  val agents: ObservableCollection[T] = service.getAgents
  agents.onElementAdded(onAdded)
}

or to its method

trait Agent
trait SubscriptionHandle
trait AgentService {
  def getAgents[T &lt;: Agent]: ObservableCollection[T]
}
trait ObservableCollection[T] extends util.Collection[T] {
  def onElementAdded(onAdded: Consumer[T]): SubscriptionHandle
}

def test[T &lt;: Agent](service: AgentService): Unit = {
  val onAdded: Consumer[T] = ???
  val agents: ObservableCollection[T] = service.getAgents
  agents.onElementAdded(onAdded)
}

huangapple
  • 本文由 发表于 2020年8月24日 20:47:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/63561372.html
  • bounded-wildcard
  • java
  • scala
  • scala-java-interop
  • type-conversion
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定