go - 函数参数的求值顺序是什么?

我正在使用这个版本的 Go:

$ go version
go version go1.18 windows/amd64

当struct A只有一个字段和B有两个或以上字段时,结果是不同的,只有当参数类型是interface时才会出现这种情况。

我不确定这是否是一个错误:

package main

import (
    "fmt"
)

func main() {
    a := A{}
    m("A", a, SetAI(&a))
    b := B{}
    m("B", b, SetBI(&b))
}

type A struct {
    I int
    S string
}

type B struct {
    I int
}

func SetAI(a *A) A {
    a.I = 10
    return *a
}

func SetBI(b *B) B {
    b.I = 10
    return *b
}

func m(name string, arg1, arg2 interface{}) {
    fmt.Println(name+":", arg1, arg2)
}

我期望这样的输出:

A: {10} {10}
B: {10} {10}

相反,我得到了这个:

A: {0 } {10 }
B: {10} {10}

最佳答案

混淆和不同输出的根源是参数的评估顺序。

看看你的例子:

m("A", a, SetAI(&a))

这是一个函数 call , 函数值和参数在 the usual order 中求值:

Otherwise, when evaluating the operands of an expression, assignment, or return statement, all function calls, method calls, and communication operations are evaluated in lexical left-to-right order. For example, in the (function-local) assignment

y[f()], ok = g(h(), i()+x[j()], <-c), k()

the function calls and communication happen in the order f(), h(), i(), j(), <-c, g(), and k(). However, the order of those events compared to the evaluation and indexing of x and the evaluation of y is not specified.

所以基本上规范只保证函数调用和通信 操作从左到右发生。

您的调用有参数 "A" , aSetAI(&a) .无法保证第二个参数是否为 a&a 之前评估参数传递给 SetAI() ,这非常重要,因为 SetAI()修改 a .由于无法保证顺序,您不能依赖哪个将首先被评估,这两个顺序均符合规范。

如果您通过复制before 结构来显式求值,您会得到相同的结果:

a := A{}
aCopy := a
m("A", aCopy, SetAI(&a))
b := B{}
bCopy := b
m("B", bCopy, SetBI(&b))

这将输出(在 Go Playground 上尝试):

A: {0 } {10 }
B: {0} {10}

或者,如果您希望首先评估函数调用:

a := A{}
ap := SetAI(&a)
m("A", a, ap)
b := B{}
bp := SetBI(&b)
m("B", b, bp)

这将输出 10对于每种情况(在 Go Playground 上尝试这个):

A: {10 } {10 }
B: {10} {10}

https://stackoverflow.com/questions/71762407/

相关文章:

c++ - 临时初始化和引用初始化

haskell - 在 Haskell 中日志记录功能的不同实现之间切换的有效方法?

authentication - 是 CQRS 中的登录/注册命令或查询

java - 如何使用 Collectors.collectionAndThen 和 Collect

java - 如何在 Java 中创建包含运算符的变量?

c# - 使用 EF Core 按 Id 检索实体的通用方法

c - 在格式控制字符串中使用消息

python - `__ge__` 在 dict.values() 上使用时失败

c# - System.IO.Directory.Exists 在 LINQ 语句中失败,但在 fo

python - 将列表附加到现有数据框