我尝试将命名参数传递给来自常规Scala对象(如string / list / map)的函数,其中参数的名称及其值都是可变的(在我的情况下来自解析)用户输入)。有没有办法在Scala中执行此操作?我主要在scala中寻找一个简短的程序,类似于python:
def surprise(animal, color):
print('Oh, a ' + color + ' ' + animal + '!')
arguments = {'animal': 'cat', 'color': 'black'}
surprise(**arguments)
由于python可以将字典解包为命名参数,因此会产生
Oh, a black cat!
我一直在scala中搜索此功能,但我找不到它。任何人都可以举例说明如何在scala中实现这个目标吗?
提前致谢!
答案 0 :(得分:1)
我想说,这并不像python那么容易,但我会尝试提出几种解决方案。您需要从类型和订单的json(或其他用户输入)中提取参数。例如,可以使用helper case class和play-json:
来完成def surprise(animal: String, color: String): Unit = {
println(s"Oh, a $color $animal!")
}
import play.api.libs.json.{JsValue, Json}
case class FuncArguments(animal: String, color: String)
implicit val funcArgumentsFormat = Json.format[FuncArguments]
implicit def jsValueToFuncArguments(json: JsValue): FuncArguments =
json.as[FuncArguments]
def surprise2(json: JsValue): Unit = {
(surprise _).tupled(FuncArguments.unapply(json).get)
}
案例类与您的方法具有相同的签名。 implicit val funcArgumentsFormat
是play-json格式,用于将数据提取到case类中(不安全,因为as
。如果在json中缺少必需的参数名称/类型,将抛出异常),隐式def jsValueToFuncArguments转换你的json进入案例类(理论上也是不安全的,因为Option.get
,但不认为你可以在这里得到异常)。并帮助函数surprise2将json转换为参数。
另一种方法是,例如,使用一些反射:
import play.api.libs.json.{JsValue, Json}
class SomeClass {
def surprise(animal: String, color: String): Unit = {
println(s"Oh, a $color $animal!")
}
}
def surprise3(json: JsValue): Unit = {
val method = classOf[SomeClass].getMethods.find(_.getName == "surprise").get
val params = method.getParameters
val values = params.map(_.getName).map(name => (json \ name).as[String])
val ref = new SomeClass
method.invoke(ref, values: _*)
}
在这个例子中,我们假设所有字段都具有相同的类型String
,您的函数在类中。 Play-json用于解析。获取方法而不是参数名称,而不是提取参数的值(与参数的顺序相同),而不仅仅是将它们应用于函数。
并致电:
val json = Json.obj("animal" -> "cat", "color" -> "black")
surprise2(json)
surprise3(json)