Go中的短路评估

pet*_*r96 5 go short-circuiting

我对短路评估的理解是只在if语句中需要时调用表达式.Go会跟着这个吗?

例如,我平均可以从以下方面获得更好的表现:

if !isValidQueryParams(&queries) || r == nil || len(queries) == 0 {
    return "", fmt.Errorf("invalid querystring")
}
Run Code Online (Sandbox Code Playgroud)

......对此:

if r == nil || len(queries) == 0 || !isValidQueryParams(&queries) {
    return "", fmt.Errorf("invalid querystring")
}
Run Code Online (Sandbox Code Playgroud)

...因为这isValidQueryParams是一个比r == nil测试地图长度要多得多的功能?

也就是说,解释员首先会评估r == nil,看到它是真的而不是费心去评估其他条件吗?

编辑:错误地将短路评估称为惰性评估

mkr*_*er1 6

这称为短路评估。根据本教程,布尔运算符使用以下代码:

尽管在Go语言规范中并未明确声明Go使用短路评估,但确实提到了

逻辑运算符适用于布尔值,并产生与操作数相同类型的结果。正确的操作数是有条件的。

这是一个简单的例子,证明Go使用短路评估

[…]


kos*_*tix 5

您所指的是"短圈评估" - 也就是说,只有在完整结果可用时才使用正常关联性规则评估子表达式,并且其余表达式的评估不会根据其改变到有问题的二元运算符的规则.

Go确实实现了逻辑表达式的短路评估(参见其他答案).

(@icza评论:有点相关:Go代码中有短路评估,但Go的模板引擎不使用短路评估.详细信息:Golang模板和有效字段测试.)

"懒惰评估"完全是另一回事 - 通常在所谓的"功能"编程语言中实现,并且它不直接在Go中实现.


话虽如此,我注意到虽然Go没有直接(如语法和运行时)对延迟评估的支持,但它可以在需要的地方使用.

例如,您可能有一个goroutine从一个频道中读取可能无限数量的项目,并以某种方式处理它们,以及另一个goroutine或其中几个 - 产生这些值并通过该频道发送它们.这样,只在接收端"实现"的值不会比实际准备好处理更快.


pet*_*r96 5

感谢Kostix和mkrieger的回答-他们是正确的,我指的是短路评估,而不是惰性评估。

Go确实实现了正常的短路评估,可以通过以下代码得出:

package main

import "fmt"

func main() {
    for i := 0; i < 10; i++ {
        if testFunc(1) || testFunc(2) {
            // do nothing
        }
    }
}

func testFunc(i int) bool {
    fmt.Printf("function %d called\n", i)
    return true
}
Run Code Online (Sandbox Code Playgroud)

...这将始终带来:

$ function 1 called
$ function 1 called
$ function 1 called
$ function 1 called
$ function 1 called
$ function 1 called
$ function 1 called
$ function 1 called
$ function 1 called
$ function 1 called
Run Code Online (Sandbox Code Playgroud)