Golang 將改變常見的 closure 地雷

在「Fixing for loops in Go 1.22 (go.dev)」看到的,原文在「Fixing For Loops in Go 1.22」這邊。

算是各種有 closure 的程式語言會遇到的經典問題,下面的 Golang 程式在撰寫時會預期輸出 abc (不保證順序),但實際上會輸出 ccc,因為變數的 scope 設計原因:

func main() {
    done := make(chan bool)

    values := []string{"a", "b", "c"}
    for _, v := range values {
        go func() {
            fmt.Println(v)
            done <- true
        }()
    }

    // wait for all goroutines to complete before exiting
    for _ = range values {
        <-done
    }
}

這在 JavaScript 也是個經典的問題,搜「javascript closure loop」就可以看到「JavaScript closure inside loops – simple practical example」這個例子,對應的答案則是有提到 ES6let 因為改變了變數的 scope,可以用來解決這個問題。

剛好 let 也是 best practice 了,所以現在 JavaScript 這邊遇到這個問題的情況會少一些。

回到 Golang 這邊,Golang 是打算改變在 for loop 時,對應變數的 scope 來解決:

For Go 1.22, we plan to change for loops to make these variables have per-iteration scope instead of per-loop scope. This change will fix the examples above, so that they are no longer buggy Go programs; it will end the production problems caused by such mistakes; and it will remove the need for imprecise tools that prompt users to make unnecessary changes to their code.

另外因為這是 breaking compatibility 的改變 (畢竟有些程式碼是清楚知道這個特性而刻意這樣寫的),所以會有對應的措施,只有在有指定 Golang 1.22 或是更新的版本才會用新的 scope 編譯:

To ensure backwards compatibility with existing code, the new semantics will only apply in packages contained in modules that declare go 1.22 or later in their go.mod files. This per-module decision provides developer control of a gradual update to the new semantics throughout a codebase. It is also possible to use //go:build lines to control the decision on a per-file basis.

QTE 小遊戲 Looptap

Hacker News 首頁上看到這個小遊戲:「Show HN: Looptap – A minimal game to waste your time (vasanthv.com)」,如同他的標題寫的,浪費時間的小遊戲 XDDD

標題講的 QTE 是「快速反應事件」這個東西,在現在的遊戲裡面算是蠻常見的機制,是一種需要在事件有效區間反應的設計 (太早反應或是太晚反應都不行)。

在 Bash 的迴圈裡面跑 FFmpeg

Bash 的迴圈裡面跑 FFmpeg 有時候會遇到奇怪的靈異現象,發現是這個問題:「execute ffmpeg command in a loop」。

原因是當你用 while + read 產生迴圈時會有對 stdin 的操作行為,而 FFmpeg 預設也會去讀 stdin (WTF),於是兩邊就打架了。

解法是用 -nostdin 叫 FFmpeg 不要手賤去讀 stdin,這樣就可以解決這個問題。

YouTube 支援 Loop 功能 (重複播放)

在「YouTube Loop」這邊看到 YouTube 支援 Loop 了,在影片上按右鍵:

而且作者也有提到,在外嵌的影片也支援:

It also works for embedded videos.

以前要找外掛或是某些網站幫你,官方支援後省不少事 XD