3

在Java中我会写

void foo(final Set<? extends SomeClass> someObjects) { /* ... */ }

我在 Scala 中写什么?

def foo(someObjects : Set[AnyRef[SomeClass])

但这不起作用

4

3 回答 3

6

我发现自己很少再写这样的代码了。原因是,在你的例子中

void foo(final Set<? extends SomeClass> someObjects) { /* ... */ }
//                ^^^^^^^^^^
//                use-site variance annotation

方差注释表示您只能访问集合,不能更新它。您很可能可以按如下方式重写该方法

void foo(final Collection<? extends SomeClass> someObjects) { /* ... */ }

也就是说,如果您只能访问集合中的元素,那么您不太可能需要它是Set. 在 scala 中,这意味着使用IterableTraversable- 但Scala 中的这些类型在它们的类型参数中是协变的(它们被声明Iterable[+A]-+是一个声明站点方差注释)。因此不需要使用站点差异注释:

def foo(itr: Iterable[SomeClass])

然后你可以Set[SomeClassImpl]自由地传入这个方法:

scala> trait T; class S extends T
defined trait T
defined class S

scala> def foo(itr: Iterable[T]) = println(itr.isEmpty)
foo: (itr: Iterable[T])Unit

scala> Set(new S)
res1: scala.collection.immutable.Set[S] = Set(S@e1ed5b)

scala> foo(res1)
false

scalaSet[A]不是协变的原因A是它实现了A => Boolean(即Function1),它的输入是逆变的。因此Set[A]在 中必须是不变的A。以前有个笨蛋问过这个问题

事实上,我现在将它Set用作谓词函数的实现细节更为常见。因此,例如:

def bar(p: SomeClass => Boolean)

在这种情况下;你可以使用:

scala> bar(res1.toSet[T])
于 2012-06-15T14:35:44.590 回答
5

直译为

void foo(final Set<? extends SomeClass> someObjects) { /* ... */ }

def foo(someObjects: Set[_ <: SomeClass]) { /* ... */ }

或者

def foo(someObjects: Set[_ <: SomeClass]): Unit = { /* ... */ }

如果您要覆盖 Java 类中的某些方法,override请在def. 如果你不是,请考虑以不同的方式做事,正如其他答案所解释的那样。

于 2012-06-15T18:50:24.750 回答
3

您可以使用类型绑定来定义依赖项:

def foo[A <: SomeClass]( someObjects: Set[A] ): Unit = ...

这里A <: SomeClass的意思是Aextends SomeClass,你可以用B >: SomeClassB应该的超类来表达SomeClass

于 2012-06-15T14:21:12.593 回答