1

所以我正在使用 play Twirl 模板(不在游戏中;独立项目),并且我有一些模板可以生成一些数据库 DDL。以下作品:

if(config.params.showDDL.isSupplied) {
    print( BigSenseServer.config.options("dbms") match {
      case "mysql" => txt.mysql(
        BigSenseServer.config.options("dbDatabase"),
        InetAddress.getLocalHost().getCanonicalHostName,
        BigSenseServer.config.options("dboUser"),
        BigSenseServer.config.options("dboPass"),
        BigSenseServer.config.options("dbUser"),
        BigSenseServer.config.options("dbPass")
      )
      case "pgsql" => txt.pgsql(
        BigSenseServer.config.options("dbDatabase"),
        InetAddress.getLocalHost().getCanonicalHostName,
        BigSenseServer.config.options("dboUser"),
        BigSenseServer.config.options("dboPass"),
        BigSenseServer.config.options("dbUser"),
        BigSenseServer.config.options("dbPass")
      )
      case "mssql" => txt.mssql$.MODULE$(
        BigSenseServer.config.options("dbDatabase"),
        InetAddress.getLocalHost().getCanonicalHostName,
        BigSenseServer.config.options("dboUser"),
        BigSenseServer.config.options("dboPass"),
        BigSenseServer.config.options("dbUser"),
        BigSenseServer.config.options("dbPass")
      )
    })

    System.exit(0)
}

但是我有很多重复的陈述。如果我尝试将 case 分配给一个变量并使用 $.MODULE$ 技巧,我会收到一条错误消息,指出我的变量不带参数:

val b = BigSenseServer.config.options("dbms") match {
      case "mysql" => txt.mysql$.MODULE$
      case "pgsql" => txt.pgsql$.MODULE$
      case "mssql" => txt.mssql$.MODULE$
}
b("string1","string2","string3","string4","string5","string6")

和错误:

BigSense/src/main/scala/io/bigsense/server/BigSenseServer.scala:32: play.twirl.api.BaseScalaTemplate[T,F] 与 play.twirl.api.Template6[A,B,C,D,E ,F,Result] 不带参数

简化此 Scala 代码的最佳方法是什么?

编辑:使用以下答案组合的最终解决方案

下面的答案建议创建工厂类,但我真的想避免这种情况,因为我已经有了 Twirl 生成的模板对象。部分应用的函数让我更好地理解了如何实现这一点。事实证明,我需要做的就是选择apply方法并进行 eta 扩展;必要时结合部分功能应用。以下效果很好:

  if(config.params.showDDL.isSupplied) {

    print((config.options("dbms") match {
      case "pgsql" => 
        txt.pgsql.apply _
      case "mssql" => 
        txt.mssql.apply _
      case "mysql" => 
        txt.mysql.apply(InetAddress.getLocalHost().getCanonicalHostName,
                        _:String, _:String, _:String,_:String, _:String)
    })(
        config.options("dbDatabase"),
        config.options("dboUser"),
        config.options("dboPass"),
        config.options("dbUser"),
        config.options("dbPass")
    ))

    System.exit(0)
  }
4

2 回答 2

1

您可以尝试使用eta-expansion部分应用函数

给定一个带有一些方法的工厂:

class Factory {
  def mysql(i: Int, s: String) = s"x: $i/$s"
  def pgsql(i: Int, s: String) = s"y: $i/$s"
  def mssql(i: Int, j: Int, s: String) = s"z: $i/$j/$s"
}

您可以抽象出这样的方法:

val factory = new Factory()

// Arguments required by all factory methods
val i = 5
val s = "Hello"

Seq("mysql", "pgsql", "mssql").foreach {
  name =>

    val f = name match {
      case "mysql" =>
        // Eta-expand: Convert method into function
        factory.mysql _

      case "pgsql" =>
        factory.pgsql _

      case "mssql" =>
        // Argument for only one factory method
        val j = 10
        // Eta-expand, then apply function partially
        factory.mssql(_ :Int, j, _: String)
    }

    // Fill in common arguments into the new function
    val result = f(i, s)
    println(name + " -> " + result)
}

正如您在“mssql”案例中看到的,参数甚至可能不同;但是公共参数只需要传递一次。foreach循环只是为了测试每种情况,正文中的代码显示了如何部分应用函数。

于 2015-02-26T14:09:13.840 回答
0

您可以尝试通过使用tupled()创建函数的元组版本来执行此操作。

object X {
  def a(x : Int, y : Int, z : Int) = "A" + x + y + z
  def b(x : Int, y : Int, z : Int) = "B" + x + y + z
  def c(x : Int, y : Int, z : Int) = "C" + x + y + z
}

val selectedFunc = X.a _

selectedFunc.tupled((1, 2, 3)) //returns A123

更具体地说,您可以将参数存储在一个元组中:

val params = (BigSenseServer.config.options("dbDatabase"), 
              InetAddress.getLocalHost().getCanonicalHostName) //etc.

然后在你的比赛声明中:

case "mysql" => (txt.mysql _).tupled(params)
于 2015-02-26T10:50:28.050 回答