scala - 在 Scala 中键入伴随对象

标签 scala types companion-object

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

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/

相关文章:

scala - Akka 消息传递时序

scala - sbt - 添加在 build.sbt 之外定义的任务键

android - "Parcelable protocol requires a Parcelable.Creator object called CREATOR"(我有 CREATOR)——在 Kotlin 中

oop - Kotlin - 是否可以在类中的 init block 之前初始化伴随对象?

java - 静态内部类与 Companion 的内部类

scala - Spark Streaming - 刷新静态数据

c# - 只接受声明了一些接口(interface)的类型

Haskell类型的具体数据构造函数

haskell - TypeLits 或 Singletons : Promoting an `Integer` to `KnownNat` (`Nat` ) at Runtime

scala - 从 scala 调用 java 泛型函数