是否可以使用字符串按名称设置函数的参数。
例如:
给定:
def foo(a: String, b: String)
我可以用像这样的地图动态调用这个函数吗
Map(("a", "bla"), ("b", "blub"))
?
如果是这样,怎么做?
谢谢!
是否可以使用字符串按名称设置函数的参数。
例如:
给定:
def foo(a: String, b: String)
我可以用像这样的地图动态调用这个函数吗
Map(("a", "bla"), ("b", "blub"))
?
如果是这样,怎么做?
谢谢!
将 args 映射反射性地应用于方法:
apm@mara:~/tmp$ scalam
Welcome to Scala version 2.11.0-M4 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val m = Map(("a", "bla"), ("b", "blub"))
m: scala.collection.immutable.Map[String,String] = Map(a -> bla, b -> blub)
scala> import reflect.runtime._
import reflect.runtime._
scala> import universe._
import universe._
scala> class Foo { def foo(a: String, b: String) = a + b }
defined class Foo
scala> val f = new Foo
f: Foo = Foo@2278e0e7
scala> typeOf[Foo].member(TermName("foo"))
res0: reflect.runtime.universe.Symbol = method foo
scala> .asMethod
res1: reflect.runtime.universe.MethodSymbol = method foo
scala> currentMirror reflect f
res2: reflect.runtime.universe.InstanceMirror = instance mirror for Foo@2278e0e7
scala> res2 reflectMethod res1
res3: reflect.runtime.universe.MethodMirror = method mirror for Foo.foo(a: String, b: String): java.lang.String (bound to Foo@2278e0e7)
scala> res1.paramss.flatten
res5: List[reflect.runtime.universe.Symbol] = List(value a, value b)
scala> .map(s => m(s.name.decoded))
res7: List[String] = List(bla, blub)
scala> res3.apply(res7: _*)
res8: Any = blablub
请注意,您需要展平参数列表,paramss.flatten
. 这是一个有序的参数列表,您可以轻松地将其映射到您的参数。
巧妙的命名约定paramss
旨在传达多重嵌套;就个人而言,我的发音好像是用paramses
英语拼写的。
但现在我看到它拼写出来,我可能会发音为与埃及法老押韵。
好的,这里有反射。它并没有通过 a 完全绑定每个参数名称Map
,但是您必须按顺序保持带有参数值的序列,因此第一个值是 for a
,第二个是 forb
等等。我想说这已经足够接近了
一切都取自这里,实际上它是 Mirrors 上的极好资源。
scala> import scala.reflect.runtime.{ universe => ru }
import scala.reflect.runtime.{universe=>ru}
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala> class Bar { def foo(a : String, b : String) { println(a + ", " + b + "!")
}}
defined class Bar
scala> val instanceMirror = ru.runtimeMirror(getClass.getClassLoader).reflect(new Bar)
instanceMirror: reflect.runtime.universe.InstanceMirror = instance mirror for Bar@47f3b292
scala> val fooMethod = typeOf[Bar].declaration(newTermName("foo")).asMethod
fooMethod: reflect.runtime.universe.MethodSymbol = method foo
scala> val method = instanceMirror.reflectMethod(fooMethod)
method: reflect.runtime.universe.MethodMirror = method mirror for Bar.foo(a: String, b: String): scala.Unit (bound to Bar@47f3b292)
scala> val args = Seq("Hey", "you")
args: Seq[String] = List(Hey, you)
scala> method(args: _*)
Hey, you!
res0: Any = ()
如果该方法返回任何内容,没问题,但返回类型将是Any
(docs):
scala> class Bar { def foo(a : String, b : String) = a + b }
defined class Bar
scala> val instanceMirror = ru.runtimeMirror(getClass.getClassLoader).reflect(ne
w Bar)
instanceMirror: reflect.runtime.universe.InstanceMirror = instance mirror for Bar@642e0260
scala> val fooMethod = typeOf[Bar].declaration(newTermName("foo")).asMethod
fooMethod: reflect.runtime.universe.MethodSymbol = method foo
scala> val method = instanceMirror.reflectMethod(fooMethod)
method: reflect.runtime.universe.MethodMirror = method mirror for Bar.foo(a: String, b: String): java.lang.String (bound to Bar@642e0260)
scala> val args = Seq("Testing", "concatenation")
args: Seq[String] = List(Testing, concatenation)
scala> method(args: _*)
res5: Any = Testingconcatenation
没有反射,你的设置:
val valmap = Map (("a", "bla"), ("b", "blub"))
def foo (a: String, b: String) = a + "-baz-" + b
一个负责名称映射的函数:
def fmap (m: Map[String, String]) : String = (m.get("a"), m.get ("b")) match {
case (Some(s), Some (t)) => foo (s, t)
case _ => "didn't match"
}
调用:
fmap (valmap)
// res0: String = bla-baz-blub
比 fmap 更好的名称(可能与 flatmap 混淆)可能有用。请注意,地图不保证包含某些键,因此我们不会得到字符串,而是返回字符串的选项。
名称在编译时不能保证匹配,函数最后会用 s 和 t 调用。但有时您可能需要这样的功能,并且有内部证明,“a”和“b”在地图中。当然,您可以使用任意名称调用每个期望 2 个字符串的方法,最简单的方法是使用 b,a 而不是 a,b:
// ...
case (Some(s), Some (t)) => foo (t, s)
// ...
使用数组的类似方法:
val arr: Array[String] = (Seq.fill ('c')("not initialized")).toArray
arr('a')="bla"
arr('b')="blub"
def fmap (ar: Array[String]) : String = foo (ar('a'), ar('b'))
fmap (arr)
Seq.fill ('c')... 将数组从 '\0' 填充到 'b',所以你得到一个非常稀疏的数组,只是为了处理 2 个值。如果将其填充到“z”,则可以动态调用该函数:
def fmap (ar: Array[String], c1: Char, c2: Char) : String = foo (ar(c1), ar(c2))
fmap (arr, 'a', 'b')
fmap (arr, 'b', 'a')
fmap (arr, 'a', 'a')
fmap (arr, 'i', 't')
等等。