如何将元组声明为函数的返回类型以及如何在scala中调用调用者代码中的元组?

时间:2011-07-05 15:56:44

标签: scala

假设我有一个scala函数,它应该返回一个类型的元组 (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

}

在来电代码中:

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.

代码不完整。那么我如何声明并返回函数中的元组以及如何在上面的场景中使用?

即使地图看起来更合适,在上面的情况下是否建议使用元组?

尽管我得到了所有的答案,但没有答案解决了如何在代码中声明元组和填充元组的问题(不会在时间声明中将值赋给元组,如此答案所示:

var (words, row, col) =  if(someValue) {
  getResults(someValue)
} else {
  getResults(someOtherValue)
}

这是代码的一部分仍然没有答案:

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
    }

5 个答案:

答案 0 :(得分:19)

可以在syntactically simple fashion(依赖于元组类型'unapply方法)中执行多个分配,如下所示:

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

因此,您只需将后一个示例更改为:

var (words, row, col) =  if(someValue) {
  getResults(someValue)
} else {
  getResults(someOtherValue)
}

if语句将返回(String, Int, Int),相关组件将按顺序分配到wordsrowcol

如果您询问如何使用返回类型注释方法声明,那也很容易:

def getResult(param: Int): (String, Int, Int) = {
   ...
}

至于它是否更好地作为地图 - 完全取决于你的方法的语义。您是一次返回多个值(元组)还是返回键和值之间的关联(地图)?无论哪个人觉得最自然和最方便的是你应该使用的(至少在没有其他顾虑的情况下)。

答案 1 :(得分:6)

首先,您需要决定是否需要地图。

你可能想要一张地图,因为

  1. 每次都会获得不同的键值对
  2. 你有很多关键值对,需要迭代它们来管理它们
  3. 您拥有数据的键值,而不仅仅是代码的一部分,需要检索相应的值
  4. 到目前为止,它看起来并不像这三种情况中的任何一种。所以你真的不需要 map ,你需要一个名称来处理不同类型的数据。 (也就是说,您可以让编译器处理您的名称和相应数据之间的映射。)

    获取命名值的最直接方法是使用案例类:

    case class Result(words: String, row: Int, col: Int) {}
    

    你可以退货:

    def getResult = Result("an example", 1, 10)
    

    您可以指定:

    val result = getResult
    

    并查看部分:

    println(result.words)  // Prints "an example"
    

    您可以为各个部分分配单独的变量:

    val Result(w,r,c) = getResult    // Now w=="an example", r==1, w==10
    

    您可以模式匹配以找到部分答案:

    getResult match {
      case Result(_,1,c) => println("Had 1 row and "+c+" columns)
      case _ => println("I don't know what to do with this")
    }
    

    您可以按名称复制和更改:

    getResult.copy(words = "another example")
    

    等等。

    如果您不需要名称,可以使用元组,它们以相同的方式工作,但只知道参数的位置。第一项称为_1,第二项称为_2,依此类推。您只需在括号中列出项目即可指定这些:

    def getResult = ("an example", 1, 10)
    

    你可以做以上所有事情,除了使用基于位置的名字:

    println(getResult._3)   // Prints 10
    

答案 2 :(得分:5)

当你有一个需要返回多个值的函数并且这些值不需要作为一个结构保持在一起时,返回值作为返回值非常有用(如果它们需要保持在一起它会更有意义定义一个简单的案例类。)

要声明一个以3元组作为返回类型的函数并返回一个3元组,你会这样做:

def getResults(param: Int) : (String, Int, Int) = {
  ...
  (stringval, intval1, intval2)
}

这实际上是语法糖:

def getResults(param: Int) : Tuple3[String, Int, Int] = {
  ...
  new Tuple3[String,Int,Int](stringval, intval1, intval2)
}

Scala有N:1到22的TupleN类

答案 3 :(得分:2)

我是否正确地假设您希望首先声明结果变量(并且需要在if / else构造之外访问它们),然后调用设置和使用它们的代码(在if / else构造内)?如果是这样,它应该像

一样简单
var words: String = _
var row: Int = _
var col: Int = _
...
if (someValue) {
  (words, row, col) = getResults(someValue)
  // use words, row, col
} else {
  (words, row, col) = getResults(someOtherValue)
  // use words, row, col
}

答案 4 :(得分:1)

元组没问题,但您也可以考虑案例类:

case class Result( words: String, row: Int, col: Int ) 

它是不可变的,并且具有许多有用的功能。我更喜欢case类而不是元组,因为字段有用。在此处了解详情:http://www.codecommit.com/blog/scala/case-classes-are-cool