我有一个类及其伴生对象,它们一起具有一些可重用的功能。我已经将伴生对象的功能封装成一个特征,所以现在的情况是这样的
class Foo {
import Foo._
def foo: Quux = bar(this)
}
trait Bar {
def bar(f: Foo): Quux = frobnicate(f)
}
object Foo extends Bar
由于
Foo.foo
是一种可重用的方法,我想把它放到它的 trait 中。但是我必须想办法告诉类型检查器,尽管
bar
不是类 Foo
上的方法,它将在范围内,因为从伴随对象导入。我想我需要一些东西,比如能够在类的伴随对象上打字。有没有类似的东西?
最佳答案
有多种方法可以对 Scala 中所需的抽象进行建模。我将首先描述最简单的模式并分析您的问题,然后我将描述最复杂的模式,它用于 Scala 集合。
首先要注意的是,伴生对象是放置代码的正确位置,您需要在没有类实例的情况下调用该代码,而排除 的位置 helper 您在 中使用的实例 方法是性状 .此外,智能 scala 编译器将为您的 trait 生成一个静态方法,并将所有将使用它的类链接到它。
从您的代码的角度来看,很容易看出如何将其分解为特征,然后通过使用自类型表示法,可以强制仅当特征 Bar 混合时才能混合特征 FooTrait也是。
class Foo extends FooTrait with Bar
trait FooTrait {
self:Bar =>
def foo: Quux = bar(this)
}
trait Bar {
def bar(f: Foo): Quux = frobnicate(f)
}
另请注意,如果您不想通过 Foo 类公开 Bar 接口(interface),另一种方法如下
class Foo extends FooTrait {
protected val barrer = Foo
}
trait FooTrait {
protected val barrer:Bar
def foo: Quux = barrer.bar(this)
}
trait Bar {
def bar(f: Foo): Quux = frobnicate(f)
}
object Foo extends Bar
当您采用单个类和单个伴随对象时,第二种方法工作正常,但当您想要开发类层次结构时,您现在有一个可用于这些类中的每一个的伴随对象,并且您还想要强制伴生对象相对于“伴生类”具有某些特征。
还有一种更复杂的方法,用于 Scala 集合,我强烈建议您不要使用,除非绝对必要。
让我们从 GenTraversable 开始:
trait GenTraversable[+A]
extends GenTraversableLike[A, GenTraversable[A]]
with GenTraversableOnce[A]
with GenericTraversableTemplate[A, GenTraversable]
{
def seq: Traversable[A]
def companion: GenericCompanion[GenTraversable] = GenTraversable
}
object GenTraversable extends GenTraversableFactory[GenTraversable] {
implicit def canBuildFrom[A] = new GenericCanBuildFrom[A]
def newBuilder[A] = Traversable.newBuilder
}
如您所见,特征定义了一个伴生对象,它为构建相同类型的新集合(通常用于过滤、映射等)提供了一些基本的基础设施。
通过在层次结构中向上,您可以看到
def companion
精炼:trait GenIterable[+A]
extends GenIterableLike[A, GenIterable[A]]
with GenTraversable[A]
with GenericTraversableTemplate[A, GenIterable]
{
def seq: Iterable[A]
override def companion: GenericCompanion[GenIterable] = GenIterable
}
object GenIterable extends GenTraversableFactory[GenIterable] {
implicit def canBuildFrom[A] = new GenericCanBuildFrom[A]
def newBuilder[A] = Iterable.newBuilder
}
如果您在类之间浏览,您将了解该机制用于保证对于每个具体的集合实现,在范围内都有一个伴生,该伴生具有与类本身相关的某种属性。这是可能的,因为在子类中细化方法的返回类型是合法的。
然而,为了正常工作,这个机制需要一些手动转换和大量通用参数,以及通用签名。
trait GenericTraversableTemplate[+A, +CC[X] <: GenTraversable[X]] extends HasNewBuilder[A, CC[A] @uncheckedVariance] {
protected[this] def newBuilder: Builder[A, CC[A]] = companion.newBuilder[A]
/** The generic builder that builds instances of $Coll
* at arbitrary element types.
*/
def genericBuilder[B]: Builder[B, CC[B]] = companion.newBuilder[B]
private def sequential: TraversableOnce[A] =this.asInstanceOf[GenTraversableOnce[A]].seq
// other code
}
关于scala - 在 Scala 中键入伴随对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12179092/