〰️
bufio/NewReaderとos/StdinでCLから入力を取得する
GoではPythonのinput()
みたいにコマンドライン(CL)から入力を取得するにはどうすればいいのだろうと思っていたので、CLからの入力値を合計する簡単な関数を作ってみます!
CLからの標準I/O
GoではCLからの入出力とエラーをos
パッケージのStdin
、Stdout
、Stderr
でそれぞれ以下のように定義されています。
var (
Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)
https://pkg.go.dev/os#pkg-variables
今回はCLの入力を扱うので、Stdin
とエラーハンドリングでStderr
を使用します。
bufio/NewReader
入力をメモリに保存するCLから得た入力はio.Reader
で値を取得しますが、今回は取得値をメモリに保存するバッファ付きI/Oのbufio
パッケージを使用します。
バッファというメモリを介することで、ハードディスクなどに保存するよりも高速にデータの入出力が可能になります。
sumNumbers()
の実装
CLからの入力値を合計するまずは必要なパッケージをインポートします。
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
sumNumbers()
は以下のように実装してみました。
func sumNumbers() (int, error) {
fmt.Println("Please enter numbers one by one, followed by Enter. Enter 0 to end input:")
var sum int
// 標準入力から数値を読み込んでメモリに格納
reader := bufio.NewReader(os.Stdin)
for {
// 入力された数値を文字列として取得
input, err := reader.ReadString('\n')
if err != nil {
return 0, err
}
// 入力された文字列からスペースを削除
// '\n'がスペースとして残っているため削除しないとのちの`Atoi()`でエラーになる
input = strings.TrimSpace(input)
// 0を入力したらループを抜ける
if input == "0" {
break
}
// 入力された文字列を数値に変換
num, err := strconv.Atoi(input)
if err != nil {
fmt.Printf("Invalid number: %s\n", input)
continue
}
sum += num
}
return sum, nil
}
流れとしては以下のような感じです。
-
CLからの入力値
input
を文字列として取得し、メモリに格納する -
input
を整形してstrconv.Atoi()
でint
型に変換する -
Stdin
が0になればそれまでの入力値を合計して返す
main()
で実行
main()
を以下のように実装して、プログラムを実行します。
func main() {
sum, err := sumNumbers()
if err != nil {
// 標準エラー出力にエラーメッセージを表示し、プログラムを終了
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
fmt.Printf("Sum: %d\n", sum)
}
実行結果は以下のようになりました。
Please enter numbers one by one, followed by Enter. Enter 0 to end input:
1
2
3
0
Sum: 6
まとめ
今回はbufio
パッケージとos/Stdin
を使ってCLからの入力を取得してデータ処理する関数を実装しました。
Pythonはこれをinput()
だけでできたはずなので、改めてPythonのパッケージの豊富さと便利さに気付かされます。。。
Discussion
こんにちは。
bufio
を使うのであれば、bufio.Scanner
を使うのが便利だと思います。恥ずかしながら知りませんでした、、便利ですね😮
例のコードまで書いてくださりありがとうございます!!