英文:
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) {
// ...
}
}
还有一个返回ObservableCollection
的AgentService.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<T> implements Collection<T> {
public SubscriptionHandle onElementAdded(Consumer<T> onAdded) {
// ...
}
}
And an AgentService.java
that returns an ObservableCollection:
public interface AgentService {
ObservableCollection<? extends Agent> getAgents();
}
Now, I am trying to use this ObservableCollection.java
in a Scala project like this:
def test(service: AgentService): Unit = {
val onAdded: Consumer[_ <: Agent] = ???
service.getAgents.onElementAdded(onAdded)
}
Trying this results in the following compilation error:
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
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 <: 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
答案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) // 无法编译
x
和 y
都具有存在类型,但 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[_ <: 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)
// ^^^^^^^
}
//type mismatch;
// found : java.util.function.Consumer[_$2] where type _$2 <: 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'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 <: 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)
}
or to its method
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)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论