あふん

ぷろぐらむとか

Golang の terminal パッケージで file descriptor を引数として渡すときは int にキャストしよう

f:id:ponde_m:20190322033947j:plain:w300

先日、こんなコードを見つけたのでキャストいらないのではって PR を送ったら、キャストしないとWindows でダメだったって言われたので調べてみました。

terminal.ReadPassword(int(syscall.Stdin))

Issue

github.com

cannot use syscall.Stdin (type syscall.Handle) as type int in argument to terminal.IsTerminal

こういう怒られ方をするらしいです。

GoDoc を見てみる

golang.org

var (
        Stdin  = 0
        Stdout = 1
        Stderr = 2
)

なるほど int。ってなるけどこれは Linux 用のドキュメントらしいです。

https://go-review.googlesource.com/c/tools/1371

この変更で GoDoc にパラメータで GOOSGOARCH を渡せるようになったらしいのでみてみます。

https://golang.org/pkg/syscall/?GOOS=windows#pkg-variables

var (
        Stdin  = getStdHandle(STD_INPUT_HANDLE)
        Stdout = getStdHandle(STD_OUTPUT_HANDLE)
        Stderr = getStdHandle(STD_ERROR_HANDLE)
)

getStdHandle の定義はこうなっています。

func getStdHandle(h int) (fd Handle) {
    r, _ := GetStdHandle(h)
    CloseOnExec(r)
    return r
}
func GetStdHandle(stdhandle int) (handle Handle, err error)

完全に理解した。

なのでキャストしないと

cannot use syscall.Stdin (type syscall.Handle) as type int in argument to terminal.IsTerminal

って怒られ方をするんですね。

おまけ

github.com

unconvert という不要なキャストを検知してくれる Linter があるんですが、オプションで -all を渡すと GOOS/GOARCH の組み合わせまで見てくれて、全ての場合で不要の時のみ怒ってくれるらしい。かしこい。