在Go语言的if语句中混用:=和=的含义是什么?

huangapple go评论81阅读模式
英文:

Mixing := and = in Go if statements

问题

Go语言有一个常见的习语,看起来像这样:

if val, err := func(); err != nil {
    /* val 和 err 在作用域内 */
    ...
}
/* val 和 err 不再在作用域内 */

使用了"短变量声明"。我肯定是一个粉丝。它感觉类似于在C++中做以下操作:

/* 不涉及 val 的代码 */
{
    int val;

    if ((val = func()) == ERR_VALUE) {
        /* 处理错误 */
    }
    /* 使用 val 做一些事情 */
}
/* 不涉及 val 的更多代码 */

让我困惑的是,在 if 的第一个子句中有多个变量的情况下,它们必须具有相同的作用域,也就是说,你必须这样做:

var err error
var val string

if val, err = func(); err != nil {
...

或者

if val, err := func(); err != nil {
...

一个非常常见的用例似乎是,你想在 if 的第一个子句中设置一个变量,检查是否有错误,如果没有错误,则继续执行程序流程(并能够使用在执行 if 时分配的任何值)。但是,我觉得,如果你想这样做,你必须要么:

  1. 使用一个临时变量,然后在 else 中分配给持久变量的值:
var val

if tempval, err := func(); err != nil {
    /* 处理错误 */
} else {
    val = tempval
}
  1. 声明 err 变量的作用域超出 if,如上所示。

第一种选项似乎有些笨拙-被迫使用一个"else"子句只是为了确保值不会超出作用域-而第二种选项则放弃了限制变量作用域的优势。更有经验的Go程序员在这种(看似非常常见的)情况下使用什么习惯用法呢?

英文:

Go has a common idiom that looks like this:

if val, err := func(); err != nil {
    /* val and err are in scope */
...
}
/* val and err are no longer in scope */

using "short assignment". I'm certainly a fan. It feels similar to doing:

/* code not involving val */
{
    int val;

    if ((val = func()) == ERR_VALUE) {
        /* Process the error */
    }
    /* Do something with val */
}
/* more code not involving val */

in C++. What trips me up is that, in the case where there is more than one variable in the first clause of the if, they have to have the same scope, i.e. you have to do either:

var err error
var val string

if val, err = func(); err != nil {
...

or

if val, err := func(); err != nil {
...

A very common use case would seem to be where you have a variable that you'd like to set in the first clause of the if, test for an error, and if there is none, continue with the rest of the program flow (and be able to use whatever values you assigned in executing the if). But, it seems to me, if you want to do that, you have to either:

  1. Use a temporary variable, and then assign the persistent variable value inside an else:

    var val
    
    if tempval, err := func(); err != nil {
        /* Process the error */
    } else {
        val = tempval
    }
    
  2. Declare the err variable with scope that extends past the if, as above.

The first option seems clunky - being forced to use an "else" clause just to make sure that the value doesn't fall out of scope - and the second throws away the advantages of limiting the scope of the variables. What idioms do more experienced Go programmers use for this (seemingly very common) situation?

答案1

得分: 4

《Go编程语言规范》中介绍了"If"语句的用法。根据布尔表达式的值,"If"语句指定了两个分支的条件执行。如果表达式的值为true,则执行"if"分支;否则,如果存在的话,执行"else"分支。

表达式前面可以有一个简单语句,在表达式求值之前执行。

如果你无法利用特殊形式:

if val, err := fnc(); err != nil {
    // ...
}

那么可以使用常规形式:

val, err := fnc()
if err != nil {
    // ...
}

常规形式是Go语言中必需且常见的形式。特殊形式是常规形式的一种特殊情况,为了方便而存在,但并非必需。如果特殊形式比常规形式更方便使用,则可以使用它。否则,请使用常规形式。

Go是一种块结构的编程语言,其源流可以追溯到Algol 60、C、Pascal、Modula 2和Oberon。

因此,你可以这样编写代码:

x := false
{
    x := true
    if x {
        fmt.Println(x)
    }
}
fmt.Println(x)

或者等效地使用特殊形式:

x := false
if x := true; x {
    fmt.Println(x)
}
fmt.Println(x)

两种情况下的输出结果都是:

true
false

更多详细信息可以参考《Go编程语言规范》中的相关章节。

英文:

> The Go Programming Language Specification
>
> If statements
>
> "If" statements specify the conditional execution of two branches
> according to the value of a boolean expression. If the expression
> evaluates to true, the "if" branch is executed, otherwise, if present,
> the "else" branch is executed.
>
> IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
> .
>
> if x > max {
> x = max
> }
>
> The expression may be preceded by a simple statement, which executes
> before the expression is evaluated.
>
> if x := f(); x < y {
> return x
> } else if x > z {
> return z
> } else {
> return y
> }


If you can't take advantage of the special form,

if val, err := fnc(); err != nil {
    // ...
}

then use the regular form,

val, err := fnc()
if err != nil {
    // ... 
}

The regular form is the Go language necessary and usual form. The special form is a specialization, for convenience, of the regular form; it's not necessary. If the special form is more convenient to use than the regular form, use it. Otherwise, use the regular form.


Go is a block-structured programming language tracing it's ancestry back to Algol 60, C, Pascal, Modula 2, and Oberon.

The Go Programming Language Specification

Blocks

Declarations and scope

Therefore, you can write

x := false
{
	x := true
	if x {
		fmt.Println(x)
	}
}
fmt.Println(x)

or, equivalently, as a convenience,

x := false
if x := true; x {
	fmt.Println(x)
}
fmt.Println(x)

The output in both cases is

true
false

huangapple
  • 本文由 发表于 2016年2月5日 06:50:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/35213208.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定