7

我有一个类及其伴生对象,它们一起具有一些可重用的功能。我已经将伴生对象的功能封装成一个特征,所以现在的情况是这样的

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它不是 class 上的方法Foo,但它会在范围内,因为它是从伴随对象导入的。我想我需要一些东西,比如能够在类的伴随对象上打字。

有没有类似的东西?

4

2 回答 2

8

有多种方法可以对 Scala 中所需的抽象进行建模。我将首先描述最简单的模式并分析您的问题,然后我将描述最复杂的模式,它用于 Scala 集合。

首先要注意的是,伴生对象是放置您需要调用的代码的正确位置,而无需类的实例,而在实例方法中使用的帮助器的位置是特征。此外,智能 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 接口,另一种方法如下

  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
}
于 2012-08-29T14:04:18.933 回答
2

也许你需要一个自我类型

trait Foo { self: Bar => // This says that anything that will mix in Foo
                         // must mix in Bar too.
  def foo: Quux = bar(this)
}

trait Bar {
  def bar(f: Foo): Quux = frobnicate(f)
}

object Foo extends Foo with Bar
于 2012-08-29T13:58:32.340 回答