如何使用 Scala 的 AnyVal 调用 Java 可变参数方法?
How to call a Java varargs method with Scala's AnyVal?
我有一个使用以下签名的 Java 方法(来自 jOOQ):
Query query(String sql, Object... bindings);
现在,我想在 Scala 中用 AnyVal
调用这个方法,例如:
val id = 2
val value = 3.14
query(someString, id, value)
这样做会给我以下编译器错误:
Error:(34, 16) overloaded method value query with alternatives:
(x: String,x: org.jooq.QueryPart*)org.jooq.Query <and>
(x: String,x: Object*)org.jooq.Query
cannot be applied to (String, Int, Double)
create.query(someString, id, lat)
^
但是我可以将每个 AnyVal
显式转换为 AnyRef
以强制自动装箱,从而消除编译器错误:
query(someString, id.asInstanceOf[AnyRef], value.asInstanceOf[AnyRef])
意识到这一点后,我虽然可以编写一个小函数,将所有对象转换为 AnyRef
,如下所示:
def toVarargs(arg: Any, args: Any*): Array[AnyRef] = {
(arg +: args).map(_.asInstanceOf[AnyRef]).toArray
}
query(someString, toVarargs(id, value))
遗憾的是,这并不适用,因为 Array[AnyRef]
被解释为单个可变参数变量(将其更改为 Array[Object]
没有任何区别)。
可以使用 _*
运算符来完成这项工作:
query(someString, toVarargs(id, value): _*)
然而,这似乎相当冗长。是否有更优雅的解决方案来解决这个问题,或者我无法将自己的函数与可变参数运算符结合起来?
对于 jOOQ 3.7,Conversions
type of the jOOQ-scala extension 中有一个新的 SQLInterpolation
class。它本质上只是:
implicit class SQLInterpolation(val sc : StringContext) extends AnyVal {
def sql(args: Any*) : SQL =
DSL.sql(string, args.asInstanceOf[Seq[AnyRef]] : _*)
def condition(args : Any*) : Condition =
DSL.condition(string, args.asInstanceOf[Seq[AnyRef]] : _*)
def table(args : Any*) : Table[Record] =
DSL.table(string, args.asInstanceOf[Seq[AnyRef]] : _*)
def query(args : Any*) : Query =
DSL.query(string, args.asInstanceOf[Seq[AnyRef]] : _*)
def resultQuery(args : Any*) : ResultQuery[Record] =
DSL.resultQuery(string, args.asInstanceOf[Seq[AnyRef]] : _*)
private def string = {
val pi = sc.parts.iterator
val sb = new StringBuilder(pi.next())
var i = 0;
while (pi.hasNext) {
sb += '{'
sb ++= (i toString)
sb += '}'
sb ++= pi.next()
i = i + 1;
}
sb.result
}
}
使用这个,你应该能够写:
val id = 2
val value = 3.14
query"""SELECT * FROM t WHERE id = ${id} and value = ${value}"""
上述方法的优点在于,它既适用于上述绑定值,也适用于嵌入式 SQL:
val id = 2
val value = 3.14
val condition = (MY_TABLE.ID === id) and (MY_TABLE.VALUE === value)
query"""SELECT * FROM t WHERE ${condition}"""
我有一个使用以下签名的 Java 方法(来自 jOOQ):
Query query(String sql, Object... bindings);
现在,我想在 Scala 中用 AnyVal
调用这个方法,例如:
val id = 2
val value = 3.14
query(someString, id, value)
这样做会给我以下编译器错误:
Error:(34, 16) overloaded method value query with alternatives:
(x: String,x: org.jooq.QueryPart*)org.jooq.Query <and>
(x: String,x: Object*)org.jooq.Query
cannot be applied to (String, Int, Double)
create.query(someString, id, lat)
^
但是我可以将每个 AnyVal
显式转换为 AnyRef
以强制自动装箱,从而消除编译器错误:
query(someString, id.asInstanceOf[AnyRef], value.asInstanceOf[AnyRef])
意识到这一点后,我虽然可以编写一个小函数,将所有对象转换为 AnyRef
,如下所示:
def toVarargs(arg: Any, args: Any*): Array[AnyRef] = {
(arg +: args).map(_.asInstanceOf[AnyRef]).toArray
}
query(someString, toVarargs(id, value))
遗憾的是,这并不适用,因为 Array[AnyRef]
被解释为单个可变参数变量(将其更改为 Array[Object]
没有任何区别)。
可以使用 _*
运算符来完成这项工作:
query(someString, toVarargs(id, value): _*)
然而,这似乎相当冗长。是否有更优雅的解决方案来解决这个问题,或者我无法将自己的函数与可变参数运算符结合起来?
对于 jOOQ 3.7,Conversions
type of the jOOQ-scala extension 中有一个新的 SQLInterpolation
class。它本质上只是:
implicit class SQLInterpolation(val sc : StringContext) extends AnyVal {
def sql(args: Any*) : SQL =
DSL.sql(string, args.asInstanceOf[Seq[AnyRef]] : _*)
def condition(args : Any*) : Condition =
DSL.condition(string, args.asInstanceOf[Seq[AnyRef]] : _*)
def table(args : Any*) : Table[Record] =
DSL.table(string, args.asInstanceOf[Seq[AnyRef]] : _*)
def query(args : Any*) : Query =
DSL.query(string, args.asInstanceOf[Seq[AnyRef]] : _*)
def resultQuery(args : Any*) : ResultQuery[Record] =
DSL.resultQuery(string, args.asInstanceOf[Seq[AnyRef]] : _*)
private def string = {
val pi = sc.parts.iterator
val sb = new StringBuilder(pi.next())
var i = 0;
while (pi.hasNext) {
sb += '{'
sb ++= (i toString)
sb += '}'
sb ++= pi.next()
i = i + 1;
}
sb.result
}
}
使用这个,你应该能够写:
val id = 2
val value = 3.14
query"""SELECT * FROM t WHERE id = ${id} and value = ${value}"""
上述方法的优点在于,它既适用于上述绑定值,也适用于嵌入式 SQL:
val id = 2
val value = 3.14
val condition = (MY_TABLE.ID === id) and (MY_TABLE.VALUE === value)
query"""SELECT * FROM t WHERE ${condition}"""