在Scala中的伴生对象上键入

在Scala中的伴生对象上键入,scala,types,companion-object,Scala,Types,Companion Object,我有一个类和它的伴生对象,它们一起具有一些可重用的功能。我已经将同伴对象的功能封装到一个trait中,所以现在的情况如下 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中,所以现在的情况如下

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

有这样的吗?

也许你需要一个


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

首先要注意的是,伴随对象是放置您需要调用的代码的正确位置,而无需类的实例,而在实例方法中使用的助手的位置是traits。此外,智能scala编译器将为您的trait生成一个静态方法,并将使用它的所有类链接到它

从代码的角度来看,很容易看出如何将其分解为特征,然后通过使用自类型表示法,可以强制要求仅当特征条也混合时,才能混合特征足迹

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
}
如您所见,trait定义了一个伴生对象,它为构建相同类型的新集合(通常用于过滤、映射等)提供了一些基本的基础结构

通过在层次结构中向上移动,您可以看到
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
}

trait-GenericTraversableTemplate[+A,+CC[X]你能澄清一下你希望在最后拥有的特质是什么吗?我不知道你想把
foo
方法放在哪里。在一个新的特质中?是的,我想把它放在一个单独的特质中。哇,这是一个非常好的答案!非常感谢你!:-)
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
}