Skip to content

Go 入出力

go
package main

import "fmt"

func main() {
   fmt.Println("Hello 世界!")
}

当サイトの最初の入門例は文字列の出力でした。このセクションでは、Go での入出力方法について説明します。

ファイルディスクリプタ

go
var (
   Stdin  = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
   Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
   Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)

os パッケージには 3 つの外部公開されたファイルディスクリプタがあります。型はすべて *os.File で、それぞれ以下の通りです。

  • os.Stdin - 標準入力
  • os.Stdout - 標準出力
  • os.Stderr - 標準エラー

Go での入出力はこれらなしには成り立ちません。

出力

Go には多くの出力方法があります。以下にいくつかの一般的な方法を紹介します。

stdout

標準出力はそれ自体がファイルであるため、文字列を直接標準出力に書き込むことができます。

go
package main

import "os"

func main() {
  os.Stdout.WriteString("hello world!")
}

print

Go には 2 つの組み込み関数 printprintln があります。これらは引数を標準エラーに出力します。デバッグ専用であり、一般的には推奨されません。

go
package main

func main() {
  print("hello world!\n")
  println("hello world")
}

fmt

最も一般的な用法は fmt パッケージを使用することです。fmt.Println 関数を提供しており、デフォルトで引数を標準出力に出力します。

go
package main

import "fmt"

func main() {
  fmt.Println("hello world!")
}

この関数の引数は任意の型をサポートしています。型が String インターフェースを実装している場合、String メソッドを呼び出して文字列表現を取得します。そのため、出力されるコンテンツの可読性が高く、ほとんどの状況に適しています。ただし、内部でリフレクションを使用しているため、パフォーマンスが重要な状況での多用は推奨されません。

bufio

bufio はバッファリングされた出力方法を提供します。データをまずメモリに書き込み、一定の閾値に達してから指定された Writer に出力します。デフォルトのバッファサイズは 4KB です。ファイル IO、ネットワーク IO の際にはこのパッケージの使用を推奨します。

go
func main() {
  writer := bufio.NewWriter(os.Stdout)
  defer writer.Flush()
  writer.WriteString("hello world!")
}

fmt パッケージと組み合わせて使用することもできます。

go
func main() {
  writer := bufio.NewWriter(os.Stdout)
  defer writer.Flush()
  fmt.Fprintln(writer, "hello world!")
}

フォーマット

Go のフォーマット出力機能は基本的に fmt.Printf 関数によって提供されます。C 系言語を学んだことがあれば、馴染み深いでしょう。以下に簡単な例を示します。

go
func main() {
  fmt.Printf("hello world, %s!", "jack")
}

以下は Go が現在サポートしているすべてのフォーマット動詞です。

番号フォーマット説明受信型
1%%パーセント記号 % を出力任意
2%sstring/[] byte 値を出力string,[] byte
3%q文字列をフォーマット。出力される文字列の両端に二重引用符 "" が付きますstring,[] byte
4%d10 進整数値を出力整数型
5%f浮動小数点数を出力浮動小数点型
6%e科学記数法形式で出力。複素数にも使用可能浮動小数点型
7%E%e と同じ浮動小数点型
8%g状況に応じて %f または %e を出力。余分な 0 を削除浮動小数点型
9%b整数の 2 進数表現を出力数値型
10%#b2 進数の完全な表現を出力数値型
11%o整数の 8 進数表現を出力整数型
12%#o整数の完全な 8 進数表現を出力整数型
13%x整数の小文字 16 進数表現を出力数値型
14%#x整数の完全な小文字 16 進数表現を出力数値型
15%X整数の大文字 16 進数表現を出力数値型
16%#X整数の完全な大文字 16 進数表現を出力数値型
17%v値の元の形式を出力。主にデータ構造の出力に使用任意
18%+v構造体を出力する際にフィールド名を追加任意
19%#v完全な Go 構文形式の値を出力任意
20%t布尔値を出力布尔型
21%T値に対応する Go 言語の型値を出力任意
22%cUnicode コードポイントに対応する文字を出力int32
23%U文字に対応する Unicode コードポイントを出力rune,byte
24%pポインタが指すアドレスを出力ポインタ型

fmt.Sprintf または fmt.Printf を使用して文字列をフォーマットまたはフォーマットされた文字列を出力します。いくつかの例を見てみましょう。

go
fmt.Printf("%%%s\n", "hello world")

fmt.Printf("%s\n", "hello world")
fmt.Printf("%q\n", "hello world")
fmt.Printf("%d\n", 2<<7-1)

fmt.Printf("%f\n", 1e2)
fmt.Printf("%e\n", 1e2)
fmt.Printf("%E\n", 1e2)
fmt.Printf("%g\n", 1e2)

fmt.Printf("%b\n", 2<<7-1)
fmt.Printf("%#b\n", 2<<7-1)
fmt.Printf("%o\n", 2<<7-1)
fmt.Printf("%#o\n", 2<<7-1)
fmt.Printf("%x\n", 2<<7-1)
fmt.Printf("%#x\n", 2<<7-1)
fmt.Printf("%X\n", 2<<7-1)
fmt.Printf("%#X\n", 2<<7-1)

type person struct {
    name    string
    age     int
    address string
}
fmt.Printf("%v\n", person{"lihua", 22, "beijing"})
fmt.Printf("%+v\n", person{"lihua", 22, "beijing"})
fmt.Printf("%#v\n", person{"lihua", 22, "beijing"})
fmt.Printf("%t\n", true)
fmt.Printf("%T\n", person{})
fmt.Printf("%c%c\n", 20050, 20051)
fmt.Printf("%U\n", '')
fmt.Printf("%p\n", &person{})

他の基数を使用する際は、% とフォーマット動詞の間にスペースを追加することで区切り文字の効果を達成できます。

go
func main() {
  str := "abcdefg"
  fmt.Printf("%x\n", str)
  fmt.Printf("% x\n", str)
}

この例の出力結果は

61626364656667
61 62 63 64 65 66 67

数値を使用する際は、自動的にゼロを補完することもできます。

go
fmt.Printf("%09d", 1)
// 000000001

2 進数も同様です。

go
fmt.Printf("%09b", 1<<3)
// 000001000

エラー状況

フォーマット文字数 < 引数リスト数

go
fmt.Printf("", "") //%!(EXTRA string=)

フォーマット文字数 > 引数リスト数

go
fmt.Printf("%s%s", "") //%!s(MISSING)

型が一致しない

go
fmt.Printf("%s", 1) //%!s(int=1)

フォーマット動詞が不足

go
fmt.Printf("%", 1) // %!(NOVERB)%!(EXTRA int=1)

入力

以下に一般的な入力方法を紹介します。

read

ファイルを直接読み取るのと同様に、入力コンテンツを読み取ることができます。

go
func main() {
  var buf [1024]byte
  n, _ := os.Stdin.Read(buf[:])
  os.Stdout.Write(buf[:n])
}

この使い方は非常に面倒であり、一般的には推奨されません。

fmt

fmt パッケージが提供するいくつかの関数を使用できます。使い方は C 言語と似ています。

go
// os.Stdin から読み取られたテキストをスキャン。スペースで区切ります。改行もスペースとして扱います
func Scan(a ...any) (n int, err error)

// Scan と似ていますが、改行でスキャンを停止します
func Scanln(a ...any) (n int, err error)

// フォーマットされた文字列に従ってスキャンします
func Scanf(format string, a ...any) (n int, err error)

2 つの数値を読み取ります。

go
func main() {
  var a, b int
  fmt.Scanln(&a, &b)
  fmt.Printf("%d + %d = %d\n", a, b, a+b)
}

固定長の配列を読み取ります。

go
func main() {
  n := 10
  s := make([]int, n)
  for i := range n {
    fmt.Scan(&s[i])
  }
  fmt.Println(s)
}
1 2 3 4 5 6 7 8 9 10
[1 2 3 4 5 6 7 8 9 10]

bufio

大量の入力を読み取る必要がある場合は、bufio.Reader を使用してコンテンツを読み取ることを推奨します。

go
func main() {
    reader := bufio.NewReader(os.Stdin)
    var a, b int
    fmt.Fscanln(reader, &a, &b)
    fmt.Printf("%d + %d = %d\n", a, b, a+b)
}

scanner

bufio.Scannerbufio.Reader に似ていますが、行単位で読み取ります。

go
func main() {
  scanner := bufio.NewScanner(os.Stdin)
  for scanner.Scan() {
    line := scanner.Text()
    if line == "exit" {
      break
    }
    fmt.Println("scan", line)
  }
}

結果は以下の通りです。

first line
scan first line
second line
scan second line
third line
scan third line
exit

TIP

入出力の練習をしたい場合は、洛谷 で簡単な ACM モードのアルゴリズム問題を数問解くと、すぐに慣れることができます。

Golang学习网由www.golangdev.cn整理维护