【问题标题】:Way to enhance a class with function delegation使用函数委托增强类的方法
【发布时间】:2019-09-13 12:34:18
【问题描述】:

我在 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 中有没有很好的方法来做到这一点?

谢谢。

【问题讨论】:

标签: scala scala-macros


【解决方案1】:

在 Dotty(以及未来的 Scala 3)中,它是 now available 就像

class B {
    val a: A

    export a
}

export a.{doSomething, doOtherThing}

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

【讨论】:

  • 如果两个导​​出具有相似的方法签名会怎样?
  • @Dragonborn 也许我不明白你的意思(你能举个例子吗?),但没什么特别的。
【解决方案2】:

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

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

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

也许可以使用trait 或基于宏的解决方案,但这取决于使用委托的具体原因。

【讨论】:

  • 您可以让它们像值一样简单地创建方法...def doSomething = a.doSomething 等。
【解决方案3】:

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

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
}

【讨论】:

    【解决方案4】:

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

    它是针对2.112.122.13 进行交叉编译的。对于2.112.12,您必须使用宏天堂编译插件才能使其工作。对于2.13,您需要使用标志-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)
    }
    

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

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

    【讨论】:

      猜你喜欢
      • 2011-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多