5

我在 Scala 中有以下课程:

class A {
    def doSomething() = ???

    def doOtherThing() = ???
}

class B {
    val a: A

    // need to enhance the class with both two functions doSomething() and doOtherThing() that delegates to A
    // def doSomething() = a.toDomething()
    // def doOtherThing() = a.doOtherThing()
}

我需要一种在编译时增强类 B 的方法,该类 B 具有与 A 相同的函数签名,当在 B 上调用时简单地委托给 A。

在 Scala 中有没有很好的方法来做到这一点?

谢谢你。

4

4 回答 4

7

在 Dotty(以及未来的 Scala 3)中,它现在可以简单地作为

class B {
    val a: A

    export a
}

export a.{doSomething, doOtherThing}

对于 Scala 2,遗憾的是没有内置的解决方案。正如蒂姆所说,你可以做一个,但你需要决定你愿意付出多少努力以及支持什么。

于 2019-04-24T09:55:56.570 回答
4

您可以通过为每个函数创建别名来避免重复函数签名:

val doSomething = a.doSomething _
val doOtherthing = a.doOtherThing _

然而,这些现在是函数值而不是方法,根据使用情况可能相关也可能不相关。

可以使用基于trait或基于宏的解决方案,但这取决于使用委派的细节。

于 2019-04-24T09:26:30.243 回答
4

隐式转换可以像这样用于委托

object Hello extends App {
  class A {
    def doSomething() = "A.doSomething"
    def doOtherThing() = "A.doOtherThing"
  }

  class B {
    val a: A = new A
  }

  implicit def delegateToA(b: B): A = b.a
  val b = new B
  b.doSomething() // A.doSomething
}
于 2019-04-24T10:10:59.717 回答
0

有这个宏委托宏可能正是您正在寻找的。它的目标是自动实现委托/代理模式,因此在您的示例中,您的类B必须扩展 class A

它是针对2.112.12和进行交叉编译的2.13。因为你必须使用宏天堂编译插件才能使其工作2.112.12对于2.13,您需要使用 flag-Ymacro-annotations代替。

像这样使用它:

trait Connection {
  def method1(a: String): String
  def method2(a: String): String
  // 96 other abstract methods
  def method100(a: String): String
}

@Delegate
class MyConnection(delegatee: Connection) extends Connection {
  def method10(a: String): String = "Only method I want to implement manually"
}

// The source code above would be equivalent, after the macro expansion, to the code below
class MyConnection(delegatee: Connection) extends Connection {
  def method1(a: String): String = delegatee.method1(a)
  def method2(a: String): String = delegatee.method2(a)
  def method10(a: String): String = "Only method I need to implement manually"
  // 96 other methods that are proxied to the dependency delegatee
  def method100(a: String): String = delegatee.method100(a)
}

它应该适用于大多数场景,包括涉及类型参数和多个参数列表的情况。

免责声明:我是宏的创建者。

于 2021-06-09T12:18:46.643 回答