【问题标题】:Is go evaluation order between member invocations guaranteed?是否保证成员调用之间的评估顺序?
【发布时间】:2020-02-13 20:55:25
【问题描述】:

假设我有一个带状态的结构,以及该结构上的一些成员函数。 假设 struct 成员返回一个它自己类型的实例,我在该实例上调用附加函数,并将调用初始实例上的某个其他成员的结果作为参数传递。 第一次调用和参数调用之间的调用顺序是否得到保证?

(在尝试构建具有某种内部状态的“构建器”类型对象时,这种模式经常出现,例如表达式堆栈。)

package main

import (
    "fmt"
)

type q struct {
    val int
}

func (s *q) getVal() int {
    return s.val
}

func (s *q) a() *q {
    s.val += 1
    return s
}

func (s *q) b(i int) int {
    return i + s.val
}

func main() {
    s := &q{}
    // this currently prints 2
    // but is that guaranteed?
    fmt.Println(s.a().b(s.getVal()))
}

具体来说,s.a()s.getVal() 的相对调用顺序是否得到保证? Golang 定义了“从左到右的词汇顺序”,但仅限于单个表达式,s.a().b() 在技术上似乎与s.getVal() 不同。

它目前的行为是我想要和期望的行为,但我不知道它是否也是我可以“永远”依赖的行为。

【问题讨论】:

  • 规范很容易理解:golang.org/ref/spec#Order_of_evaluation
  • 一个 goroutine 中的求值顺序是有保证的——我想不出一种语言没有。如果执行顺序未知,则程序无法运行。
  • 另外,Go 1 Compatibility Promise 表示现在可以运行的程序在任何 Go 1.x 版本下都不会停止运行。改变评估行为的顺序显然会破坏这个承诺。
  • 尽管值得指出的是,任何严重依赖于评估顺序的代码对于任何阅读它的开发人员来说都不必要地难以推理,并且应该重构设计以使其更容易理解并且更少容易出错。
  • 是的,但是整个文档太长,无法粘贴到评论中,这就是我链接到它的原因

标签: go method-call expression-evaluation


【解决方案1】:

the spec的相关部分是:

所有函数调用、方法调用和通信操作都按照从左到右的词汇顺序进行计算。

在包级别,初始化依赖项会覆盖单个初始化表达式的从左到右规则,但不会覆盖每个表达式中的操作数:

【讨论】:

  • 感谢 Flimzy 确认函数调用部分仍然适用于编译器可能看起来独立的不同值。这当然意味着编译器无法进行大量优化,但对于具有任意副作用的语言来说,这感觉像是正确的权衡。 (这就是为什么我通常更喜欢排序不重要或明确的语言,比如 Haskell。)
猜你喜欢
  • 2013-10-18
  • 2011-08-30
  • 2018-11-20
  • 1970-01-01
  • 1970-01-01
  • 2016-11-24
  • 2014-07-25
  • 2020-04-21
  • 2011-07-13
相关资源
最近更新 更多