【问题标题】:Multiple-value in single-value context error returning a variable and a multiple-return function单值上下文中的多值错误返回一个变量和一个多返回函数
【发布时间】:2019-09-12 14:10:55
【问题描述】:

我正在尝试返回一个变量以及一个返回多个值的函数。

考虑这个人为的例子:

func twoInts() (int, int) {
    return 2, 3
}
func threeInts() (int, int, int) {
    return 1, twoInts()
}

调用threeInts()返回“单值上下文中的多值twoInts()”。

我知道我可以执行以下操作

func twoInts() (int, int) {
    return 2, 3
}
func threeInts() (int, int, int) {
    num1, num2 := twoInts()
    return 1, num1, num2
}

但我试图理解为什么返回是单值上下文。

Go 是否认为 return 是 int, (int, int)?有没有办法扩展第一个函数返回,使其返回int, int, int

【问题讨论】:

  • 原始代码中的 twoInts() 代替了第二个返回值。第三个返回值完全丢失的事实被第一个“单值上下文中的多值”错误所隐藏。没有比你已经想出来的更短的版本了。

标签: go


【解决方案1】:

https://golang.org/ref/spec#Return_statements

从具有结果类型的函数返回值有三种方式:

  1. 一个或多个返回值可能在“return”语句中明确列出。每个表达式必须是单值的并且可以分配给 函数结果类型的对应元素。

  2. “return”语句中的表达式列表可能是对多值函数的一次调用。效果就像每个返回的值 从那个函数被分配给一个临时变量,其类型为 各自的值,后跟一个“return”语句列表 这些变量,此时适用上一个案例的规则。

  3. 如果函数的结果类型为其结果参数指定名称,则表达式列表可能为空。结果参数作用 作为普通的局部变量,函数可以为它们赋值 有必要的。 “return”语句返回这些值 变量。

这三种方法中没有一种允许将单值表达式与对多值函数的调用混合在一起。


“有没有办法扩展第一个函数返回,使其返回 int, int, int?” 不,没有。

【讨论】:

    【解决方案2】:

    为什么它不起作用的简单答案是因为规范不允许。该规范允许您返回多个值,这些值是另一个函数调用的返回值,但它们必须在数字上匹配并且必须可分配给每个结果。 Spec: Return statement:

    “return”语句中的表达式列表可能是对多值函数的一次调用。 效果就像从该函数返回的每个值都分配给具有相应值类型的临时变量,然后是列出这些变量的“return”语句,此时的规则以前的情况适用。

    将带有值的return 语句视为assignment,请参阅上面引用中的强调,并且:

    在执行任何延迟函数之前设置结果参数的“return”语句指定结果。

    如果结果参数的数量和类型与左侧的变量列表匹配,则赋值也只允许右侧的函数调用:

    元组赋值将多值运算的各个元素分配给变量列表。有两种形式。首先,右手操作数是单个多值表达式,例如函数调用channelmap 操作,或type assertion。左侧操作数的数量必须与值的数量匹配。

    [...] 在第二种形式中,左边的操作数的数量必须等于右边的表达式的数量,每个表达式都必须是单值,而 右边的第n个表达式被赋值给左边的第n个操作数...

    问题“为什么不允许你想要的东西?”有点基于意见。它可以与作业一起被支持,但在语言设计阶段被“排除”了。这与将参数传递给函数调用几乎相同。如果您想将返回值作为参数传递给另一个函数,那么如果它们在数字和类型上匹配(请参阅Spec: Calls)是可能的。你想要的需要这些东西才能工作:a, b, c, d := f(), g()f(g(), h())。有讨论,这里是Robert Griesemer's words:

    此外,您假设您的建议是“改进”。这远非确定。需要明确的是,当前的规则是经过深思熟虑的,也是经过深思熟虑的。您可以放心,我们在语言设计期间(2007 年至 2009 年)考虑了您的建议。如果您的建议被允许,那么 f(g(), h()) 会怎样,其中 g 和 h 返回多个恰好与 f 的参数列表匹配的值?可能也应该被允许。然后我们还应该允许这样的事情:“a, b, c, d := f(), g()” 否则我们会有另一个不一致的地方。等等。允许这样做当然是可能的,但它也为意外错误打开了大门。例如,函数的参数列表可能会以意想不到的方式发生变化,而代码可能仍然可以工作,从而隐藏错误。所以这里务实的解决方案是允许一小组相当安全的规则,而不是允许一切可能的规则。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-04
      • 2011-05-10
      • 2016-06-30
      • 2016-03-04
      • 1970-01-01
      • 2013-04-26
      • 2020-12-17
      • 1970-01-01
      相关资源
      最近更新 更多