简体   繁体   English

单变量表达式求值的结果是什么

[英]What is the result of a single variable expression evaluation

Running the following snippet of Go code one can realize that function foo receives the value of the first argument actually set while evaluating the second argument of the function.运行以下 Go 代码片段,可以发现 function foo在评估 function 的第二个参数时接收到实际设置的第一个参数的值。 This behavior might look counterintuitive so that we need to prove this to be a part of language spec, not something implementation-specific.这种行为可能看起来违反直觉,因此我们需要证明这是语言规范的一部分,而不是特定于实现的东西。

package main

import (
    "fmt"
)

func setVal(s *int, v int) int {
    old := *s
    *s = v
    return old
}

func foo(s int, p int) {
    fmt.Printf("s = %d, p = %d\n", s, p)
}

func main() {
    var s int
    foo(s, setVal(&s, 99))
}

Programm outputs s = 99, p = 0 , which means a modified value of variable s has been passed to the function.程序输出s = 99, p = 0 ,这意味着变量s的修改值已传递给 function。

Here is what the Go spec says regarding the case.这是 Go 规范关于此案的内容。

In a function call , ...arguments must be single-valued expressions... arguments are evaluated in the usual order.function 调用中, ...arguments 必须是单值表达式... arguments 以通常的顺序计算。 After they are evaluated, the parameters of the call are passed by value to the function... Where usual order is the lexical left-to-right order.评估后,调用的参数按值传递给 function...其中通常的顺序词法从左到右的顺序。

A variable is a storage location for holding a value.变量是保存值的存储位置。 ...A variable's value is retrieved by referring to the variable in an expression; ...通过引用表达式中的变量来检索变量的值; it is the most recent value assigned to the variable.它是分配给变量的最新值。

Therefore foo(s, setVal(&s, 99)) is a function call, variable s and function setVal() are the single-valued expressions, and s is evaluated first.因此foo(s, setVal(&s, 99))是一个 function 调用,变量s和 function setVal()是单值表达式,首先计算s The last spec statement makes one assume the result of a variable evaluation is its value, so if that is true, function foo should receive initial value of the variable s .最后一个规范语句假设变量评估的结果是它的值,所以如果这是真的,function foo应该接收变量s初始值。

But it in fact it appears that the function receives the value of the first argument been set at the moment of evaluating the second argument, which is a bit confusing.但实际上似乎 function 收到了在评估第二个参数时设置的第一个参数的值,这有点令人困惑。

Does that mean the evaluation order is broken or the result of a variable evaluation is not its value?这是否意味着评估顺序被破坏或变量评估的结果不是它的值?

What you "miss" from the spec is Spec: Calls:您从规范中“错过”的是Spec: 调用:

In a function call, the function value and arguments are evaluated in the usual order .在 function 调用中, function 值和 arguments以通常的顺序进行评估。 After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution.评估后,调用的参数按值传递给 function,被调用的 function 开始执行。

Evaluating the parameters does not mean their values are read or "taken".评估参数并不意味着它们的值被读取或“获取”。 The first parameter is s , its evaluation is s itself, but its value is not yet read.第一个参数是s ,它的求值是s本身,但它的值还没有被读取。 The second parameter is evaluated, which means setVal() is called and will modify the value of s .第二个参数被评估,这意味着setVal()被调用并将修改s的值。

Now that we have evaluated the parameters, their values are read, so s will have the value 99 .现在我们已经评估了参数,它们的值被读取,所以s的值为99

Evaluating s in the example is trivial, but of course that could be a more complex expression just like the second argument.在示例中评估s是微不足道的,但当然这可能是一个更复杂的表达式,就像第二个参数一样。 Here's a more complex example:这是一个更复杂的例子:

s, s2 := new(int), new(int)

getFunc := func() func(s int, p int) { return foo }
first := func(a, b *int) *int { return a }

getFunc()(*first(s, s2), setVal(s, 99))

Call of the last function involves the following steps:最后一个 function 的调用涉及以下步骤:

  • function value is evaluated: getFunc() is called, it's return value will be the function value评估 function 值: getFunc() ,它的返回值将是 function 值
  • parameters are evaluated: (a) first() is called, its return value is dereferenced;评估参数: (a) first()被调用,它的返回值被取消引用; (b) setVal() is called, its return value will be used (b) setVal()被调用,它的返回值将被使用
  • And now the values are taken: value of *s and the old value of s (value returned by setVal() ).现在取值: *s的值和s的旧值(由setVal()返回的值)。

This will output the same as your example, try it on the Go Playground .这将 output 与您的示例相同,请在Go Playground上尝试。

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

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