Go 入出力
package main
import "fmt"
func main() {
fmt.Println("Hello 世界!")
}当サイトの最初の入門例は文字列の出力でした。このセクションでは、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
標準出力はそれ自体がファイルであるため、文字列を直接標準出力に書き込むことができます。
package main
import "os"
func main() {
os.Stdout.WriteString("hello world!")
}print
Go には 2 つの組み込み関数 print、println があります。これらは引数を標準エラーに出力します。デバッグ専用であり、一般的には推奨されません。
package main
func main() {
print("hello world!\n")
println("hello world")
}fmt
最も一般的な用法は fmt パッケージを使用することです。fmt.Println 関数を提供しており、デフォルトで引数を標準出力に出力します。
package main
import "fmt"
func main() {
fmt.Println("hello world!")
}この関数の引数は任意の型をサポートしています。型が String インターフェースを実装している場合、String メソッドを呼び出して文字列表現を取得します。そのため、出力されるコンテンツの可読性が高く、ほとんどの状況に適しています。ただし、内部でリフレクションを使用しているため、パフォーマンスが重要な状況での多用は推奨されません。
bufio
bufio はバッファリングされた出力方法を提供します。データをまずメモリに書き込み、一定の閾値に達してから指定された Writer に出力します。デフォルトのバッファサイズは 4KB です。ファイル IO、ネットワーク IO の際にはこのパッケージの使用を推奨します。
func main() {
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()
writer.WriteString("hello world!")
}fmt パッケージと組み合わせて使用することもできます。
func main() {
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()
fmt.Fprintln(writer, "hello world!")
}フォーマット
Go のフォーマット出力機能は基本的に fmt.Printf 関数によって提供されます。C 系言語を学んだことがあれば、馴染み深いでしょう。以下に簡単な例を示します。
func main() {
fmt.Printf("hello world, %s!", "jack")
}以下は Go が現在サポートしているすべてのフォーマット動詞です。
| 番号 | フォーマット | 説明 | 受信型 |
|---|---|---|---|
| 1 | %% | パーセント記号 % を出力 | 任意 |
| 2 | %s | string/[] byte 値を出力 | string,[] byte |
| 3 | %q | 文字列をフォーマット。出力される文字列の両端に二重引用符 "" が付きます | string,[] byte |
| 4 | %d | 10 進整数値を出力 | 整数型 |
| 5 | %f | 浮動小数点数を出力 | 浮動小数点型 |
| 6 | %e | 科学記数法形式で出力。複素数にも使用可能 | 浮動小数点型 |
| 7 | %E | %e と同じ | 浮動小数点型 |
| 8 | %g | 状況に応じて %f または %e を出力。余分な 0 を削除 | 浮動小数点型 |
| 9 | %b | 整数の 2 進数表現を出力 | 数値型 |
| 10 | %#b | 2 進数の完全な表現を出力 | 数値型 |
| 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 | %c | Unicode コードポイントに対応する文字を出力 | int32 |
| 23 | %U | 文字に対応する Unicode コードポイントを出力 | rune,byte |
| 24 | %p | ポインタが指すアドレスを出力 | ポインタ型 |
fmt.Sprintf または fmt.Printf を使用して文字列をフォーマットまたはフォーマットされた文字列を出力します。いくつかの例を見てみましょう。
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{})他の基数を使用する際は、% とフォーマット動詞の間にスペースを追加することで区切り文字の効果を達成できます。
func main() {
str := "abcdefg"
fmt.Printf("%x\n", str)
fmt.Printf("% x\n", str)
}この例の出力結果は
61626364656667
61 62 63 64 65 66 67数値を使用する際は、自動的にゼロを補完することもできます。
fmt.Printf("%09d", 1)
// 0000000012 進数も同様です。
fmt.Printf("%09b", 1<<3)
// 000001000エラー状況
フォーマット文字数 < 引数リスト数
fmt.Printf("", "") //%!(EXTRA string=)フォーマット文字数 > 引数リスト数
fmt.Printf("%s%s", "") //%!s(MISSING)型が一致しない
fmt.Printf("%s", 1) //%!s(int=1)フォーマット動詞が不足
fmt.Printf("%", 1) // %!(NOVERB)%!(EXTRA int=1)入力
以下に一般的な入力方法を紹介します。
read
ファイルを直接読み取るのと同様に、入力コンテンツを読み取ることができます。
func main() {
var buf [1024]byte
n, _ := os.Stdin.Read(buf[:])
os.Stdout.Write(buf[:n])
}この使い方は非常に面倒であり、一般的には推奨されません。
fmt
fmt パッケージが提供するいくつかの関数を使用できます。使い方は C 言語と似ています。
// 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 つの数値を読み取ります。
func main() {
var a, b int
fmt.Scanln(&a, &b)
fmt.Printf("%d + %d = %d\n", a, b, a+b)
}固定長の配列を読み取ります。
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 を使用してコンテンツを読み取ることを推奨します。
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.Scanner は bufio.Reader に似ていますが、行単位で読み取ります。
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
exitTIP
入出力の練習をしたい場合は、洛谷 で簡単な ACM モードのアルゴリズム問題を数問解くと、すぐに慣れることができます。
