Go言語のfmtパッケージによる書式付き出力の完全ガイド

Go言語において、テキストの出力を制御するためには標準ライブラリの fmt パッケージが不可欠です。本記事では、fmt パッケージを活用した多様なデータ型の書式化方法や、出力幅の制御、そしてよくあるエラーへの対処法について詳しく解説します。

fmtパッケージの主要な出力関数

fmt パッケージには、用途に応じた複数の出力関数が用意されています。

  • Print: 標準出力に文字列を出力します。書式化は行いません。
  • Println: 標準出力に文字列を出力し、末尾に改行を追加します。
  • Printf: 指定された書式に従って標準出力に文字列を出力します。
  • Sprintf: 書式化された文字列を生成して返しますが、標準出力には出力しません。
  • Fprintf: 書式化された文字列を os.Stdout ではなく、指定された io.Writer に出力します。

書式化の基本は Printf 系の関数で、以下のような構文を使用します。

fmt.Sprintf("書式文字列", 引数1, 引数2, ...)

書式文字列内の % で始まるプレースホルダー(動詞)は、続く引数と順番にマッピングされます。引数の数がプレースホルダーの数と一致しない場合、実行時に警告やエラーが発生します。

appName := "MyApp"
fmt.Printf("アプリケーション名: %s\n", appName)

データ型別の書式化動詞

1. 整数の書式化

整数値は進数や文字コードとして様々な形式で出力できます。

動詞説明
%b2進数表記
%o8進数表記
%d10進数表記
%x16進数表記(小文字)
%X16進数表記(大文字)
%cUnicodeコードポイントに対応する文字
%UUnicodeフォーマット(例: U+1F600)
num := 1024
fmt.Printf("2進数: %b\n", num)
fmt.Printf("8進数: %o\n", num)
fmt.Printf("10進数: %d\n", num)
fmt.Printf("16進数(小): %x\n", num)
fmt.Printf("16進数(大): %X\n", num)

emoji := '😀'
fmt.Printf("文字: %c\n", emoji)
fmt.Printf("Unicode: %U\n", emoji)

2. 浮動小数点数の書式化

浮動小数点数は、指数表記や固定小数点表記など、目的に応じてフォーマットを選択します。

動詞説明
%e科学的記数法(小文字のe、例: -1.2e+3)
%E科学的記数法(大文字のE、例: -1.2E+3)
%f固定小数点表記(例: 123.45)
%g必要に応じて %e または %f を使用(末尾の0を省略)
%G必要に応じて %E または %f を使用(末尾の0を省略)
pi := 3.141592653589793
fmt.Printf("科学記数法(小): %e\n", pi)
fmt.Printf("科学記数法(大): %E\n", pi)
fmt.Printf("固定小数点: %f\n", pi)
fmt.Printf("最適化表記(小): %g\n", pi)
fmt.Printf("最適化表記(大): %G\n", pi)

3. ブール値の書式化

動詞説明
%ttrue または false
isActive := true
fmt.Printf("ステータス: %t\n", isActive)

4. 文字列の書式化

動詞説明
%s文字列またはバイトスライス
%qGoの構文で安全にエスケープされたダブルクォート囲みの文字列
%x16進数表記(小文字、1バイトにつき2文字)
%X16進数表記(大文字、1バイトにつき2文字)
message := "Hello, 世界"
fmt.Printf("通常: %s\n", message)
fmt.Printf("クォート: %q\n", message)
fmt.Printf("16進数(小): %x\n", message)
fmt.Printf("16進数(大): %X\n", message)

5. ポインタの書式化

動詞説明
%p0xプレフィックス付きの16進数メモリアドレス
data := "sample data"
ptr := &data
fmt.Printf("ポインタアドレス: %p\n", ptr)

6. 汎用プレースホルダー

データ型が不明な場合や、構造体などの複雑なオブジェクトを出力する際に便利です。

動詞説明
%vデフォルトのフォーマット
%+v構造体のフィールド名を含むフォーマット
%#vGoの構文表現(型情報付き)
%T値の型をGoの構文で表現
%%パーセント記号そのものを出力(プレースホルダーではない)

%v は内部でデータ型に応じたデフォルトの動詞を呼び出します。例えば、bool は %t、int は %d、string は %s として処理されます。

type Server struct {
    Host string
    Port int
}

srv := Server{Host: "localhost", Port: 8080}

fmt.Printf("デフォルト: %v\n", srv)
fmt.Printf("フィールド名付き: %+v\n", srv)
fmt.Printf("Go構文: %#v\n", srv)
fmt.Printf("型情報: %T\n", srv)
fmt.Printf("進捗: 100%%\n")

出力幅と精度の制御

テーブル形式での出力やログの整形など、文字列の幅や浮動小数点数の精度を厳密に制御したい場合があります。

文字列の幅制御

プレースホルダーと動詞の間に数値を挿入することで幅を指定します。正の数は右詰め、マイナス記号 - を付けると左詰めになります。幅が不足している場合、デフォルトではスペースで埋められます。

word := "Go"
fmt.Printf("|%s|\n", word)     // 幅指定なし
fmt.Printf("|%5s|\n", word)    // 幅5、右詰め
fmt.Printf("|%-5s|\n", word)   // 幅5、左詰め

※ 注意点: 文字列に対する 0 フラグ(例: %05s)は、Goの fmt では無視されスペースで埋められる仕様です。ゼロパディングは数値に対して使用します。

ピリオド . を使うと最大幅(文字列の截断)を指定できます。

longText := "GolangProgramming"
fmt.Printf("|%.6s|\n", longText) // 最大6文字に截断

浮動小数点数の精度制御

幅.精度 の形式で、全体の幅と小数点以下の桁数を同時に指定できます。

temperature := 36.54321
fmt.Printf("|%f|\n", temperature)      // デフォルト
fmt.Printf("|%8.2f|\n", temperature)   // 幅8、小数点以下2桁、右詰め
fmt.Printf("|%-8.2f|\n", temperature)  // 幅8、小数点以下2桁、左詰め
fmt.Printf("|%08.2f|\n", temperature)  // 幅8、小数点以下2桁、ゼロパディング

よくある書式化エラーとデバッグ

fmt.Printf 系の関数を使用する際、プレースホルダーと引数の不一致により、実行時に特別なエラー文字列が出力されることがあります。これらはコンパイルエラーにはなりませんが、バグの温床となるため注意が必要です。

1. 型の不一致または不明な動詞

指定した動詞が引数の型と一致しない場合に %!verb(type=value) が出力されます。

fmt.Printf("%d", "text") 
// 出力: %!d(string=text)

2. 引数が多すぎる

プレースホルダーの数に対して引数が多い場合、余分な引数に対して %!(EXTRA type=value) が出力されます。

fmt.Printf("Hello", "World") 
// 出力: Hello%!(EXTRA string=World)

3. 引数が不足している

プレースホルダーの数に対して引数が少ない場合、%!verb(MISSING) が出力されます。

fmt.Printf("Value: %d") 
// 出力: Value: %!d(MISSING)

4. 幅や精度の指定ミス

幅や精度に整数以外(例えば文字列や未定義の変数)を指定しようとすると、%!(BADWIDTH) や %!(BADPREC) が出力されます。

// 動的な幅指定には * を使用し、引数として整数を渡す必要があります
width := "five"
fmt.Printf("%*s", width, "data") 
// 出力: %!s(BADWIDTH)

タグ: Go FMT golang 書式化出力 printf

10月17日 03:45 投稿