在Scala中键入伴随对象

And*_*rea 7 types scala companion-object

我有一个类及其伴随对象,它们共同具有一些可重用的功能.我已将伴随对象的功能封装成特征,所以现在的情况就像

class Foo {
  import Foo._

  def foo: Quux = bar(this)
}

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

object Foo extends Bar
Run Code Online (Sandbox Code Playgroud)

既然Foo.foo是一种可重用的方法,我想把它放到它的特性中.

但我必须找到一种方法来告诉类型检查器,虽然bar不是类的方法Foo,但它将在范围内,因为从伴随对象导入.我想我需要能够键入类的伴随对象.

有类似的东西吗?

Edm*_*984 8

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

首先要注意的是,伴随对象是放置您需要调用的代码的正确位置,而不需要您的类的实例,而在实例方法中使用的辅助对象的地方是特征.此外,智能scala编译器将为您的特征生成单个静态方法,并链接将使用它的所有类.

从你的代码的角度来看,很容易看出它如何被分解成一个特征,然后通过使用自我类型表示法,可以强制只有当特征条混合时才能混合特征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)
  }
Run Code Online (Sandbox Code Playgroud)

另请注意,如果您不希望通过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
Run Code Online (Sandbox Code Playgroud)

当你使用单个类和单个伴随对象时,第二种方法可以正常工作,但是当你想要开发类的层次结构时,你现在有一个可用于这些类的每个类的伴随对象,并且你也想要强制执行伴侣对象具有"比较阶级"的某些特征.

有一种更复杂的方法,在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
}
Run Code Online (Sandbox Code Playgroud)

如您所见,该特征定义了一个伴随对象,它为构建相同类型的新集合提供了一些基本的基础结构(通常用于过滤,映射等).

通过在层次结构中上升,您可以看到它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
}
Run Code Online (Sandbox Code Playgroud)

如果你在类之间浏览,你会明白这个机制用于保证对于每个具体的集合实现,在范围内有一个伴随着类本身的某种属性.这是可能的,因为在子类中细化方法的返回类型是合法的.

然而,为了正常工作,这种机制需要一些手动转换和许多通用参数,以及通用签名.

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
}
Run Code Online (Sandbox Code Playgroud)