简体   繁体   English

如何将元组声明为 function 的返回类型以及如何在 scala 的调用方代码中访问元组?

[英]How to declare tuple as the return type of a function and how to access tuple in caller code in scala?

Suppose I have a scala function that is supposed to return a tuple of type (String, Int, Int) mapped to keys (words, row, col) :假设我有一个 scala function 应该返回一个类型为(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?那么我将如何在 function 中声明和返回元组,我将如何在上述情况下使用?

Is tuple recommended way in above case even though map seems better fit?即使 map 看起来更合适,在上述情况下是否推荐使用元组?

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
    }

Multiple assigment can be performed in a syntactically simple fashion (which relies on the Tuple types' unapply methods), as follows:多重赋值可以以语法简单的方式执行(依赖于 Tuple 类型的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

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语句将返回一个(String, Int, Int)并且相关组件将按顺序分配给wordsrowcol

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.至于作为 map 是否更好 - 这完全取决于您方法的语义。 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).无论哪一种感觉最自然和最方便,都是您应该使用的(至少在没有其他顾虑的情况下)。

First, you need to decide whether you need a map.首先,您需要确定是否需要 map。

You might want a map because你可能想要一个 map 因为

  1. You get different key-value pairs each time每次都会得到不同的键值对
  2. You have awkwardly many key-value pairs and need to iterate over them to manage them你有很多尴尬的键值对,需要遍历它们来管理它们
  3. You have key values as data , not just as part of your code, and need to retrieve the corresponding value您将键值作为数据,而不仅仅是代码的一部分,并且需要检索相应的值

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.因此,您实际上并不需要map ,您只需要为不同类型的数据命名 (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:获取命名值的最直接方法是使用案例 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.如果您不需要名称,则可以使用以相同方式工作但只知道arguments的 position 的元组。 The first item is called _1 , the second _2 , and so on.第一项称为_1 ,第二项称为_2 ,依此类推。 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

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).当您有一个 function 需要返回多个值并且这些值不需要作为一个结构保持在一起时(如果它们确实需要保持在一起,那么定义一个简单的案例类)。

To declare a function with a 3-tuple as the return type and return a 3-tuple, you would do:要声明一个 function 作为返回类型并返回一个 3 元组,您可以:

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 Scala 具有用于 N 的 TupleN 类:1 到 22

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/else 构造之外访问它们),然后调用设置和使用它们的代码(在 if/else 构造内)? 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
}

Tuples are OK but you can also consider case class:元组可以,但您也可以考虑案例 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.我更喜欢 case class 而不是元组,因为字段具有有用的名称。 Learn about it here: http://www.codecommit.com/blog/scala/case-classes-are-cool在这里了解它: http://www.codecommit.com/blog/scala/case-classes-are-cool

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM