12
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Go 事始め:標準入力

Last updated at Posted at 2016-10-15

なんだかモゾモゾとした Go への興味を持ちつつ、Scala でコレクション操作の気持ちよさを覚えたり、nodejs の http リクエストの簡単さに驚きと喜びを覚えてしまったが故に、コレクション操作ゼロ・http リクエスト一つ飛ばすのに結構な行数を必要とする Go を勉強するのがなんだか億劫になっている今日この頃。

でも頑張って勉強中

そんでもって今回は標準入力を使ってデータを読み込んで、よしなに処理して、標準出力に出力
といったプログラムを組みたかったので、折角だし Go でトライしてみた

まずは os パッケージを調べた

まずはドキュメントを調べよう。
確か Go には os って名前のパッケージがあったはず。。。。
標準入出力っていったらやっぱ os パッケージでしょー

ってことで Golang os で検索。

公式ドキュメントを無事発見して stdin でページ検索。
お、やっぱあった

でもどうやって入力読み込むのこれ?

os.Stdin はパッケージの中で Stdin = NewFile(uintptr(syscall.Stdin), "/dev/stdin") って定義されているそうな。
って事はこれは File タイプなので、 File インターフェースに紐付いたメソッドを確認。

fmfm、func (f *File) Read(b []byte) (n int, err error) とな。
とりあえず試す。

stdin.go
package main

import (
    "os"
    "fmt"
)
func main() {
    buf := []byte{}
    n, _ := os.Stdin.Read(buf)
    fmt.Println("Read", n, "lines")
    fmt.Println("Buf", string(buf))
}
$ echo "hello world!" | go run stdin.go
Read 0 lines
Buf

。。。ん?

$ echo "hello?" | go run stdin.go
Read 0 lines
Buf

あ、違う...の?

Golang stdin で調べてみた

一発だった

stdin.go
package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    stdin := bufio.NewScanner(os.Stdin)
    for stdin.Scan() {
        if err := stdin.Err(); err != nil {
            fmt.Fprintln(os.Stderr, err)
        }
        fmt.Println(stdin.Text())
    }
}

公式ドキュメントを覗いてみる と定義は
func NewScanner(r io.Reader) *Scanner となっている

。。。ん?
io.Reader?

でも渡しているのは os.Stdin で、これは File タイプ。
そして Go に継承はないらしい。。。
どういうこっちゃ?

インターフェースの便利さを(なんとなく)知る

io.Reader の定義を覗きに行くと次のような定義がある。

io.Reader
type Reader interface {
        Read(p []byte) (n int, err error)
}

ん?これさっき見た?
もっかい File タイプを調べるとやっぱりあった。

File.Read
func (f *File) Read(b []byte) (n int, err error)

あ〜、同じメソッドが定義されてるから、定義としてなくても、io.Reader と互換性があるって事で使えるのか :bulb:

自分が活用できるかはさておき納得 :stuck_out_tongue:

ちなみに (s * Scanner).Scan() は毎行読み込むのに必要

(s *Scanner).Text() は、今のバッファ内文字列を返すだけで、バッファの内容を次の行に更新するには (s *Scanner).Scan() のコールが必須。
逆に言うと (s *Scanner).Text() は必ず同じ値を返すので、変数に格納する事なくガンガン呼べる。(ある程度回数がある場合は利便性のために変数に格納した方が良いとは思うけど)(あとパフォーマンス面ではどうなるのか知らない)

12
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?