Reputation: 2915
Suppose I have a scala function that is supposed to return a tuple of type
(String, Int, Int) mapped to keys (words, row, col)
:
def getResult(param: Int) {
// a lot of logic goes here to generate tuple values
// now return the tuple
}
In caller code:
var words, row, col
if(someValue) {
getResults(someValue) // assigns the tuple values to keys words, row and col
// reference words, row and col variables here
} else
getResults(someOtherValue) // assigns the tuple values to keys words, row and col
// reference words, row and col variables here
}
// in this scope here words, row and col are defined and must have values that got assigned in above code
// do something more with words, row and col variables.
The code is incomplete. So how would I declare and return the tuple in the function and how would I use in above scenario?
Is tuple recommended way in above case even though map seems better fit?
Despite all the answers I got, no answer has addressed the issue of how do I declare tuple and fill the tuple later in the code ( not assigning values to tuple at the time declaration like this answer suggests:
var (words, row, col) = if(someValue) {
getResults(someValue)
} else {
getResults(someOtherValue)
}
This is the part of the code that remains unanswered:
var words, row, col // how do I delcare tuple here?
if(someValue) {
getResults(someValue) // assigns the tuple values to keys words, row and col
// how I do that here ?
// reference words, row and col variables here
} else
getResults(someOtherValue) // assigns the tuple values to keys words, row and col
// reference words, row and col variables here
}
Upvotes: 8
Views: 19055
Reputation: 15074
Am I right in assuming you wish to declare your result variables first (and need to access them outside the if/else construct), then call code that sets and uses them (inside the if/else construct)? If so, it should be as simple as
var words: String = _
var row: Int = _
var col: Int = _
...
if (someValue) {
val (words, row, col) = getResults(someValue)
// use words, row, col
// Note: keyword 'val' added per comments by Prometheus and John Threepwood below
} else {
val (words, row, col) = getResults(someOtherValue)
// use words, row, col
// Note: keyword 'val' added per comments by Prometheus and John Threepwood below
}
Upvotes: 2
Reputation: 167891
First, you need to decide whether you need a map.
You might want a map because
So far, it doesn't look like any of these three things are the case. So you don't really need a map, you just need a name for your different types of data. (That is, you can let the compiler handle the mapping between your name and the corresponding data.)
The most direct way to get named values is with a case class:
case class Result(words: String, row: Int, col: Int) {}
You can return this:
def getResult = Result("an example", 1, 10)
You can assign this:
val result = getResult
and look at the parts:
println(result.words) // Prints "an example"
You can assign separate variables to the pieces:
val Result(w,r,c) = getResult // Now w=="an example", r==1, w==10
You can pattern match to find partial answers:
getResult match {
case Result(_,1,c) => println("Had 1 row and "+c+" columns)
case _ => println("I don't know what to do with this")
}
You can copy and change by name:
getResult.copy(words = "another example")
and so on.
If you don't need names, you can use tuples which work the same way but only know about the position of the arguments. The first item is called _1
, the second _2
, and so on. You specify these simply by listing the items between parentheses:
def getResult = ("an example", 1, 10)
and you can do everything above, except using the position-based names:
println(getResult._3) // Prints 10
Upvotes: 6
Reputation: 40461
Tuples are OK but you can also consider case class:
case class Result( words: String, row: Int, col: Int )
It's immutable and has lots of useful features. I prefer case class over tuples, because fields have useful names. Learn about it here: http://www.codecommit.com/blog/scala/case-classes-are-cool
Upvotes: 1
Reputation: 103787
Multiple assigment can be performed in a syntactically simple fashion (which relies on the Tuple types' unapply
methods), as follows:
val (foo, bar) = ("Hello", "world")
// The above is entirely equivalent to:
// val foo = "Hello"
// val bar = "world"
//
// or:
//
// val tmp = ("Hello", "world")
// val foo = tmp._1
// val bar = tmp._2
Hence you can simply change the latter example to:
var (words, row, col) = if(someValue) {
getResults(someValue)
} else {
getResults(someOtherValue)
}
The if
statement will return a (String, Int, Int)
and the relevant components will be assigned to words
, row
and col
in order.
If you were asking about how to annotate your method declaration with the return type, that's easy too:
def getResult(param: Int): (String, Int, Int) = {
...
}
As for whether it's better as a map - that depends entirely on the semantics of your method. Are you returning several values at once (a tuple) or are you returning an association between keys and values (a map)? Whichever one feels most natural and convenient is the one that you should use (at least in the absence of other concerns).
Upvotes: 21
Reputation: 13117
Tuples as return values are useful when you have a function that needs to return more than one value and where those values won't need to remain together as a structure (if they do need to stay together it would make more sense to define a simple case class).
To declare a function with a 3-tuple as the return type and return a 3-tuple, you would do :
def getResults(param: Int) : (String, Int, Int) = {
...
(stringval, intval1, intval2)
}
This is actually syntactic sugar for:
def getResults(param: Int) : Tuple3[String, Int, Int] = {
...
new Tuple3[String,Int,Int](stringval, intval1, intval2)
}
Scala has TupleN classes for N: 1 to 22
Upvotes: 5