Scala set function parameter by name with string

You can specify function arguments by name with a string.

For instance:

Given:

def foo(a: String, b: String)

Can I call this function dynamically with a map like

Map(("a", "bla"), ("b", "blub"))

?

If so, how?

Thank!

+1
source share
3 answers

Applying an argument map is reflective to a method:

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

Please note that you want to smooth out the lists of parameters paramss.flatten. This is an ordered list of parameters that you can match with your arguments trivially.

Smart naming convention is paramssdesigned to convey multiple nesting; I personally pronounce it as if it were written paramsesin English.

, , , , .

+5

, . Map, , a, b .. ,

, 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
0

:

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" 
}

Invokation:

fmap (valmap) 
// res0: String = bla-baz-blub

, fmap, , . , , , .

, 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') 

etc.

0
source

All Articles