我有一个类及其伴随对象,它们共同具有一些可重用的功能。我已将伴随对象的功能封装成特征,所以现在情况就像
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
上的方法,但它将在范围内,因为从伴随对象导入。我想我需要能够键入类的伴随对象。
有类似的东西吗?
答案 0 :(得分: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)
}
请注意,如果您不希望通过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
}
答案 1 :(得分:2)
也许您需要self type?
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