打字了在斯卡拉同伴对象(Typing over companion object in Scala)

2019-09-21 21:27发布

我有一个类和它的同伴对象一起有一些可重复使用的功能。 我已经封装同伴对象的功能为特点,所以现在的情况是这样

class Foo {
  import Foo._

  def foo: Quux = bar(this)
}

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

object Foo extends Bar

由于Foo.foo是可重复使用的方法,我想放入它的特质。

但是,我必须找到一种方法来告诉检查的类型,虽然bar是不是在类中的方法Foo ,它会在范围,因为来自同伴对象导入。 我想,我需要这样的东西能够在键入类的同伴对象。

有什么样的?

Answer 1:

有多种方式为您在斯卡拉需要的抽象模型。 我会先介绍最简单的模式,并分析你的问题,然后我将描述最复杂的图案,这是在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)
  }

另请注意,如果你不想通过你的Foo类揭露栏界面,另一种方法是以下

  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

当你把一个类和一个同伴对象第二种方法工作得很好,但是当你要开发的类层次,你现在没有可用于每个类的同伴对象不能很好地扩展,并且还希望执行该同伴对象具有相对于所述“companed类”某些特性。

还有一个更复杂的方法,这是在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
}


Answer 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


文章来源: Typing over companion object in Scala