用函数委托增强类的方法

时间:2019-04-24 09:00:05

标签: scala scala-macros

我在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的方法,该类具有与A相同的函数签名,当在B上调用时,该函数签名简单地委托给A。

在Scala中有一种不错的方法吗?

谢谢。

4 个答案:

答案 0 :(得分:6)

在Dotty(以及未来的Scala 3)中,其简称为now available

class B {
    val a: A

    export a
}

export a.{doSomething, doOtherThing}

不幸的是,对于Scala 2,没有内置的解决方案。正如蒂姆所说,您可以做一个,但是您需要确定愿意花费多少努力以及到底要支持什么。

答案 1 :(得分:3)

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

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

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

也许可以使用trait或基于宏的解决方案,但这取决于使用委派的原因的详细信息。

答案 2 :(得分: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
}

答案 3 :(得分:0)

这个宏 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)
}

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

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