(根据讨论改写问题,原始问题如下)
Go语言规范给出了一些例子,说明在对切片和Map赋值时,原语的求值顺序对于函数调用是不确定的,但是没有一个例子提到多值返回,所以我不确定它们是否适用于这种情况。
规范中的示例
a := 1
f := func() int { a++; return a }
x := []int{a, f()} // x may be [1, 2] or [2, 2]: evaluation order between a and f() is not specified
m := map[int]int{a: 1, a: 2} // m may be {2: 1} or {2: 2}: evaluation order between the two map assignments is not specified
n := map[int]int{a: f()} // n may be {2: 3} or {3: 3}: evaluation order between the key and the value is not specified
使用规范的语言,this functions返回是否也未指定:
func run() (int, int) {
a := 1
f := func() int { a++; return a }
return a, f() // always return 1,2 OR always returns 2,2 OR can return either?
}
如果没有指定计算顺序,那么像下面这样的非玩具示例可能会在将来某个时候编译器更新时中断:
func CountRows(ctx context.Context, db *pgxpool.Pool) (int, error) {
row := db.QueryRow(ctx, "SELECT COUNT(*)")
var count int
return count, row.Scan(&count)
}
原始问题
我不清楚go语言的规范是否明确了从函数返回的值是一次返回一个还是在所有表达式都求值之后才返回。
Aka是this code保证总是输出10 <nil>
(就像它在操场上做的那样)还是它可以输出0 <nil>
?
package main
import "fmt"
func main() {
fmt.Println(run())
// Output: 10 <nil>
}
func run() (int, error) {
var i int
return i, inc(&i)
}
func inc(i *int) error {
*i = *i + 10
return nil
}
编辑
This相关问题表明规范中未指定基元返回值的求值顺序
2条答案
按热度按时间hpcdzsge1#
1.“此函数返回值也未指定吗?”
是的。正如您所发现的,语言指定了某些事情的求值顺序:
当计算表达式、赋值语句或返回语句的操作数时,所有函数调用、方法调用和通信操作都按词法从左到右的顺序计算。
当然,对于表达式、赋值语句或返回语句中的求值顺序,函数调用、方法调用或通信操作之外的任何操作都是未指定的。
1.“如果编译器更新,类似下面的非玩具示例可能在将来某个时间中断”
是的,即使编译器没有更新,如果你期望它有任何依赖于求值顺序的特定结果,那么代码已经被破坏了,因为语言并没有说代码会做你认为它会做的事情。
1.是从函数返回的值,每次“返回”一个或在计算完所有表达式后返回一个。
不需要作出这种区分。
1.“此代码是否保证始终输出
10 <nil>
(就像它在操场上所做的那样),或者它是否可以输出0 <nil>
?”是的,它可以输出
0, <nil>
,这与前面的run
示例基本相同,其中闭包f
被重构为一个名为inc
的函数。qvtsj1bj2#
是的!这真是个好问题。
编写此代码的另一种方法是
这与您可以执行以下操作的原因相同
此外,您也可以这样做,如果您将数据库事务(例如) Package 在错误处理程序中,这将非常有用
在这些情况下,可以确定顶级
return
中的项将在返回给其调用者之前进行求值