scala实现根据函数名获取函数的方法

背景

工作需要,需要编写一个配置文件来配置一些函数。这些函数会应用于特定数据只上。我们都很熟悉java怎么实现这个东西,可以用反射、或者写一堆if else判断。scala崇尚函数式编程,笔者不才。尝试用3种思路实现以供参考:

object FunctionLoaderTest {

  //函数获取器,反射实现。
  import reflect.runtime.universe._

  implicit class FunctionReflector(val functionConf: String) extends AnyVal {
    def getFunc: (Double, Double) => Double = {
      val functionConfSplit = functionConf.split("[\\(\\)]")
      val weight = try {
        if (functionConfSplit.length > 1) functionConfSplit(1).toDouble else 1.0
      } catch {
        case _: Throwable => 1.0
      }
      try {
        lazy val mirror = runtimeMirror(getClass.getClassLoader)
        lazy val instanceMirror = mirror.reflect(FunctionLoaderTest)
        lazy val methodSymbol = instanceMirror.symbol.toType.decl(TermName(functionConfSplit.head)).asMethod
        lazy val methodMirror = instanceMirror.reflectMethod(methodSymbol)

        def func(a: Double, b: Double): Double = methodMirror(weight, a, b).asInstanceOf[Double]

        func
      } catch {
        case _: Throwable => (a: Double, b: Double) => 0.0
      }
    }
  }

  //函数获取器,注册实现。
  implicit class FunctionGetterDirect(val functionConf: String) extends AnyVal {

    def getFunc: (Double, Double) => Double = {
      val functionConfSplit = functionConf.split("[\\(\\)]")
      val weight = try {
        if (functionConfSplit.length > 1) functionConfSplit(1).toDouble else 1.0
      } catch {
        case _: Throwable => 1.0
      }
      functionConfSplit.head match {
        case "add" => add(weight)
        case "multiply" => multiply(weight)
        case _ => (a: Double, b: Double) => 0.0
      }
    }
  }

  //函数获取器,复合函数实现。
  implicit class FunctionGetterComposite(val functionConf: String) extends AnyVal {

    def getFunc: (Double, Double) => Double = {
      val functionConfSplit = functionConf.split("[\\(\\)]")
      val weight = try {
        if (functionConfSplit.length > 1) functionConfSplit(1).toDouble else 1.0
      } catch {
        case _: Throwable => 1.0
      }
      (a: Double, b: Double) => {
        functionConfSplit.head match {
          case "add" => add(weight)(a, b)
          case "multiply" => multiply(weight)(a, b)
          case _ => 0.0
        }
      }
    }
  }

  def add(weight: Double)(a: Double, b: Double) = weight * (a + b)
  def multiply(weight: Double)(a: Double, b: Double) = weight * a * b

}

object Test {
  def main(args: Array[String]): Unit = {
    import FunctionLoaderTest.FunctionReflector
    println("add(2)".getFunc(2, 3))
    println("multiply(2)".getFunc(2, 3))
  }
}

反射的好处就是你新增函数不需要注册,也就是不需要match来实现类似switch的操作,这里反射加lazy主要是由于本人这个是用于spark的,spark在广播的时候会把这个复合函数广播出去,其中有部分reflection的类不可序列化,写成lazy他广播的是空,到executor用的时候才去真正执行反射。注册方式实现的结果是真正返回了那个函数,复合函数实现的是一个炒鸡复杂的函数根据情况判断调用哪个。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值