Go言語入門:効果的なGo -データ:Printing(2)-

スポンサーリンク
Go言語入門:効果的なGo -データ:Printing(2)- ノウハウ
Go言語入門:効果的なGo -データ:Printing(2)-
この記事は約7分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

本日は、Go言語を効果的に使うためのガイドラインについて解説しています。

スポンサーリンク

背景

Go言語を学び始めて、より良いコードを書きたいと思い、Go言語の公式ドキュメント「Effective Go」を知りました。これは、いわば「Goらしいコードの書き方指南書」になります。単に動くコードではなく、効率的で保守性の高いコードを書くためのベストプラクティスが詰まっているので、これを読んだ時の内容を備忘として残しました。

Printing(出力)

整数の10進数表記のようなデフォルトの変換だけが必要な場合は、万能フォーマット%v(”value”の意味)を使用できます;結果はPrintPrintlnが生成するものと全く同じです。さらに、このフォーマットは配列、スライス、構造体、マップでさえも含む任意の値を出力できます。以下は前のセクションで定義されたタイムゾーンマップの出力文です。

fmt.Printf("%v\n", timeZone)  // または単に fmt.Println(timeZone)

これは以下の出力を提供します:

map[CST:-21600 EST:-18000 MST:-25200 PST:-28800 UTC:0]

マップの場合、Printfとその仲間たちはキー順に辞書順で出力をソートします。

構造体を出力する際、修正されたフォーマット%+vは構造体のフィールドに名前を注釈し、任意の値に対して代替フォーマット%#vは値を完全なGo構文で出力します。

type T struct {
    a int
    b float64
    c string
}
t := &T{ 7, -2.35, "abc\tdef" }
fmt.Printf("%v\n", t)
fmt.Printf("%+v\n", t)
fmt.Printf("%#v\n", t)
fmt.Printf("%#v\n", timeZone)

出力:

&{7 -2.35 abc   def}
&{a:7 b:-2.35 c:abc     def}
&main.T{a:7, b:-2.35, c:"abc\tdef"}
map[string]int{"CST":-21600, "EST":-18000, "MST":-25200, "PST":-28800, "UTC":0}

(アンパサンド記号に注意してください。)その引用符付き文字列フォーマットは、string型または[]byte型の値に適用される際に%qを通じても利用できます。代替フォーマット%#qは可能であればバッククォートを代わりに使用します。(%qフォーマットは整数とルーンにも適用され、単一引用符のルーン定数を生成します。)また、%xは整数に加えて文字列、バイト配列、バイトスライスにも働き、長い16進数文字列を生成し、フォーマット内にスペース(% x)があればバイト間にスペースを入れます。

もう一つの便利なフォーマットは%Tで、これは値のを出力します。

fmt.Printf("%T\n", timeZone)

出力:

map[string]int

カスタム型のデフォルトフォーマットを制御したい場合、必要なことは型にString() stringのシグネチャを持つメソッドを定義することだけです。我々の単純な型Tに対して、それは以下のようになるかもしれません。

func (t *T) String() string {
    return fmt.Sprintf("%d/%g/%q", t.a, t.b, t.c)
}
fmt.Printf("%v\n", t)

以下の形式で出力するために:

7/-2.35/"abc\tdef"

T型のTへのポインタの両方を出力する必要がある場合、Stringのレシーバは値型でなければなりません;この例はポインタを使用しましたが、それは構造体型に対してより効率的で慣用的だからです。詳細については下記のポインタ対値レシーバのセクションを参照してください。)

解説

1. 万能フォーマット %v とは

%vは「何でも出力できる魔法のフォーマット」です:

fmt.Printf("%v\n", 123)        // 数値
fmt.Printf("%v\n", "hello")    // 文字列  
fmt.Printf("%v\n", []int{1,2,3}) // スライス
fmt.Printf("%v\n", timeZone)   // マップ

これはfmt.Printfmt.Printlnと同じ結果になります。

2. 構造体出力の3つのパターン

type T struct {
    a int
    b float64
    c string
}
t := &T{7, -2.35, "abc\tdef"}

基本出力 %v

fmt.Printf("%v\n", t)  // → &{7 -2.35 abc	def}

値だけが表示されます。

フィールド名付き %+v

fmt.Printf("%+v\n", t)  // → &{a:7 b:-2.35 c:abc	def}

どのフィールドがどの値かが分かります。

Go構文形式 %#v

fmt.Printf("%#v\n", t)  // → &main.T{a:7, b:-2.35, c:"abc\tdef"}

コードで書くときの形式で表示されます。

3. その他の便利なフォーマット

型を確認する %T

fmt.Printf("%T\n", timeZone)  // → map[string]int

変数の型が何かを調べるのに便利です。

文字列の特殊表示 %q

fmt.Printf("%q\n", "abc\tdef")  // → "abc\tdef"

エスケープ文字も見えるように表示されます。

16進数表示 %x

fmt.Printf("%x\n", "hello")     // → 68656c6c6f
fmt.Printf("% x\n", "hello")    // → 68 65 6c 6c 6f(スペース区切り)

4. カスタム出力形式の定義

自分で作った型の出力形式をカスタマイズできます:

type T struct {
    a int
    b float64
    c string
}

// String メソッドを定義
func (t *T) String() string {
    return fmt.Sprintf("%d/%g/%q", t.a, t.b, t.c)
}

t := &T{7, -2.35, "abc\tdef"}
fmt.Printf("%v\n", t)  // → 7/-2.35/"abc\tdef"

重要なポイント:

  • String() stringメソッドを定義するだけ
  • %vで出力したときに、このメソッドが自動的に呼ばれる
  • デバッグ時やログ出力時に見やすくできる

5. 実際の活用例

デバッグ時:

fmt.Printf("変数の中身: %+v\n", myStruct)  // フィールド名も見える
fmt.Printf("変数の型: %T\n", myVar)       // 型を確認

設定値の確認:

fmt.Printf("設定: %#v\n", config)  // Go構文で表示

バイナリデータの確認:

fmt.Printf("データ: % x\n", data)  // 16進数でスペース区切り

このように、%vとその仲間たちを使うことで、デバッグやログ出力が格段に楽になります。

おわりに 

本日は、Go言語を効果的に使うためのガイドラインについて解説しました。

よっしー
よっしー

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました