Reputation: 51
I'm trying to make a function that executes other functions (which return Strings
) depending on an input.
For example:
def execute(input: String) = {
val actions = Map("foo" -> someObject.doStuff(), "bar" -> someObject.doThing())
actions.get(input) }
Is there a way to make the functions in the Map
to be called only if the corresponding key exists?
Upvotes: 4
Views: 1989
Reputation: 3390
object someObject {
def doStuff() = "foo"
def doThing() = "bar"
}
//if you need a string as a return value.
//there will be empty string for missing keys
def execute(input: String):String = {
val actions = Map( "foo" -> someObject.doStuff _ ,
"bar" -> someObject.doThing _ )
actions.getOrElse(input,()=>"")()
}
//if you need an Option[String] as a return value.
//there will be None value for missing keys
def executeOption(input: String):Option[String] = {
val actions = Map( "foo" -> someObject.doStuff _ ,
"bar" -> someObject.doThing _ )
actions.get(input).map(_())
}
Upvotes: 4
Reputation: 1756
Yes, there is a way how to execute object methods inside a Map
. But you first have to put functions into the map. What you did, was putting results of object methods into your map. So your methods were executed and their results were put as values into the map.
Let's assume, that your methods are defined in this class:
class SomeObject {
def doStuff(): String = "I did stuff"
def doThing(): String = "I did a thing"
}
And you have an instance of the class:
val someObject = new SomeObject
First way, how to delay execution of these methods is to create new function using lambdas and execute methods inside these lambdas:
val actions = Map(
"foo" -> (() => someObject.doStuff()),
"bar" -> (() => someObject.doThing()),
)
You can use special syntax to convert object methods directly into lambdas:
val actions = Map(
"foo" -> someObject.doStuff _,
"bar" -> someObject.doThing _
)
If you specify type of the map explicitly, than you can get rid of the underscore too:
val actions: Map[String, () => String] = Map(
"foo" -> someObject.doStuff,
"bar" -> someObject.doThing
)
Next, you need to get the function from the map. If there is no function for the key, than use a default function - one, that always returns None
val action = actions.getOrElse(input, () => None)
And finally, you invoke the action:
action()
Upvotes: 1
Reputation: 13985
From what I can tell, you are not really looking for lazy map
. You are trying to build some kind of execution engine, which does something based on string input.
Now, the simple trick to achieve this is to have a actual functions
in your Map
and execute the corresponding function for the input string.
So, lets say you have an object A,
object A {
var i = 1
def doFirstThing(): Unit = {
i = i + 1
println(s"first thing :: $i")
}
def doSecondThing(): Unit = {
i = i - 1
println(s"second thing :: $i")
}
}
And you want to build an executor for executing doFirstThing
for input "first"
and doSecondThing
for input "second"
.
So, now you need to create functions
f1
and f2
which will execute A.doFirstThing()
and A.doSecondThing()
.
Its pretty simple actually,
scala> val f1 = () => A.doFirstThing()
// f1: () => Unit = $$Lambda$1235/1187572055@7e192338
scala> val f2 = () => A.doSecondThing()
// f2: () => Unit = $$Lambda$1236/1696761182@47df3efe
Or, you can use _
to convert def
(methods
) to functions,
scala> val f1 = A.doFirstThing _
// f1: () => Unit = $$Lambda$1317/1501701470@7306836f
scala> val f2 = A.doSecondThing _
// f2: () => Unit = $$Lambda$1318/545144829@2a3251ad
Now, you can define your map using these,
scala> def execute(input: String): Unit = {
| val map = Map(
| "first" -> f1,
| "second" -> f2
| )
|
| map.get(input).foreach(f => f())
| }
// execute: (input: String)Unit
scala> execute("first")
// first thing :: 2
scala> execute("second")
// second thing :: 1
scala> execute("second")
// second thing :: 0
scala> execute("first")
// first thing :: 1
scala> execute("first")
// first thing :: 2
And it will plainly ignore all other inputs,
scala> execute("abc")
Upvotes: 1