Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 强制实现trait以提供trait可以扩展的内部类_Scala_Inheritance - Fatal编程技术网

Scala 强制实现trait以提供trait可以扩展的内部类

Scala 强制实现trait以提供trait可以扩展的内部类,scala,inheritance,Scala,Inheritance,一个trait是否可能要求它的实现类实现一些内部类,然后可以扩展这些内部类?例如 trait BaseTrait { // not actually an "abstract class", but a requirement that // subclasses provide a class named Foo with this constructor signature abstract class Foo(bar: Bar) def normalFoo(bar: Ba

一个trait是否可能要求它的实现类实现一些内部类,然后可以扩展这些内部类?例如

trait BaseTrait {
  // not actually an "abstract class", but a requirement that
  // subclasses provide a class named Foo with this constructor signature
  abstract class Foo(bar: Bar)

  def normalFoo(bar: Bar): Foo = new Foo(bar)

  // trait needs to be able to extend the Foo class implemented by the subclass.
  // this seems to be the impossible part, as far as I can tell...
  def fancyFoo(bar: Bar): Foo with SomeMixin = new Foo(bar) with SomeMixin {
    def anExtraMethod() = println("I'm an extra!")
  }
}

object ThingA extends BaseTrait {
  class Foo(bar: Bar) {
    def getThingAStuff() = println("I'm part of ThingA")
  }
}
object ThingB extends BaseTrait {
  class Foo(bar: Bar) {
    def getThingBStuff() = println("I'm part of ThingB")
  }
}

// calling `fancyFoo` on the concrete implementations should grant
// access to the specific methods in their respective `Foo` classes,
// as well as the "extra method" that the trait adds
val aFoo: ThingA.Foo with SomeMixin = ThingA.fancyFoo(bar)
aFoo.getThingAStuff()
aFoo.anExtraMethod()

val bFoo: ThingB.Foo with SomeMixin = ThingB.fancyFoo(bar)
bFoo.getThingBStuff()
bFoo.anExtraMethod()
我想要这样做的原因是我有大量的
ThingX
类,它们目前都被迫实现自己的
fancyFoo
(以及其他类似的方法,需要将Mixin添加到它们特定的Foo类中)。我想通过将
fancyFoo
及其朋友转移到BaseTracit中来减少样板文件,但我无法想出比已经存在的内容更详细的内容


编辑:

我上面的概括可能模糊了整体意图,因此这里有一些背景:

我的实际用例围绕着对数据库模式和一些表连接逻辑进行建模。团队开始从Slick的“提升”语法转向原始sql,这个系统的出现有助于支持编写原始查询

Foo
=
TableReference
。每个
ThingX
对象表示一个特定的表,它们各自的引用类包含引用该表列的方法

SomeMixin
=
TableJoin
,它应该添加连接逻辑(即如何从另一个表访问一个表)。
ThingX
对象通常定义一个
def direct
来直接引用表(即SQL查询中
FROM
子句的开头)、一个创建
内部联接的
def FROM(someOtherRef)
,以及一个创建
左联接的
def optFrom(someOtherRef)
。这三种方法正是我试图抽象为
BaseTrait
的方法

我相信我们确实需要能够提供一个普通的
TableReference
,以及提供一个带有TableJoin的
TableReference
,因为我们有一个用于组合所有连接逻辑的实用程序,我们希望禁止没有任何连接逻辑的引用被传递到其中。在整个代码库中,普通引用有几种用法

我希望能定义一些类似于

trait TableSupport {
  type Reference <: TableReference
  trait CanMatch[Ref] {
    // corresponds to the `ON` part of a `JOIN` clause
    def matchCondition(self: Reference, other: Ref): RawSQL
  }
  def defaultAlias: String

  // All of the below would be implemented by the `TableSupport` trait
  // in terms of the `Reference` constructor and mixing in TableJoin.
  // But currently each table companion has to explicitly implement these.

  def reference(alias: String = defaultAlias): Reference = ???
  def direct(alias: String = defaultAlias): Reference with TableJoin = ???
  def from[Ref: CanMatch](ref: Ref, alias: String = defaultAlias): Reference with TableJoin = ???
  def optFrom[Ref: CanMatch](ref: Ref, alias: String = defaultAlias): Reference with TableJoin = ???
}
trait表支持{

类型引用我找到的解决方案是包装类,而不是扩展类,并且使用隐式unwrapper让我与事物交互,就像它们被扩展一样

SomeTableRef与TableJoin
变为
TableJoin[SomeTableRef]

class TableJoin[T <: TableReference](val self: T, val joinStep: RawSQL)
object TableJoin {
  import language.implicitConversions
  implicit def unwrap[T <: TableReference](tj: TableJoin[T]): T = tj.self
}

使用这种方法,我能够实现我所希望的
direct
from
optFrom
方法。

trait Base这样的方法怎么样{trait Foo;type Bar为什么需要所有这些类的普通版和高级版,为什么不让它们都高级化呢?这感觉像是一个XYproblem@Tim关于XY问题,你可能是对的。我更新了这个问题,以详细说明我的实际用例(因为从Foo和Bar的角度来概括它似乎没有什么帮助)“X”是指我希望共享几个非常相似的方法的实现,这些方法目前在30多个对象上重复。
class SomeTableRef(alias: String) extends TableReference {
  def id = column("ID")
}
val joinedRef = new TableJoin(new SomeTableRef(defaultAlias), /* raw sql */)
joinedRef.id // compiles fine because of `unwrap`