在Java中我会写
void foo(final Set<? extends SomeClass> someObjects) { /* ... */ }
我在 Scala 中写什么?
def foo(someObjects : Set[AnyRef[SomeClass])
但这不起作用
我发现自己很少再写这样的代码了。原因是,在你的例子中
void foo(final Set<? extends SomeClass> someObjects) { /* ... */ }
// ^^^^^^^^^^
// use-site variance annotation
方差注释表示您只能访问集合,不能更新它。您很可能可以按如下方式重写该方法
void foo(final Collection<? extends SomeClass> someObjects) { /* ... */ }
也就是说,如果您只能访问集合中的元素,那么您不太可能需要它是Set
. 在 scala 中,这意味着使用Iterable
或Traversable
- 但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])
直译为
void foo(final Set<? extends SomeClass> someObjects) { /* ... */ }
是
def foo(someObjects: Set[_ <: SomeClass]) { /* ... */ }
或者
def foo(someObjects: Set[_ <: SomeClass]): Unit = { /* ... */ }
如果您要覆盖 Java 类中的某些方法,override
请在def
. 如果你不是,请考虑以不同的方式做事,正如其他答案所解释的那样。
您可以使用类型绑定来定义依赖项:
def foo[A <: SomeClass]( someObjects: Set[A] ): Unit = ...
这里A <: SomeClass
的意思是A
extends SomeClass
,你可以用B >: SomeClass
比B
应该的超类来表达SomeClass
。