Go言語のフォーマット指定子まとめ

### はじめに
実装の調査などでGCPのログエクスプローラでデータ中身などを閲覧する際に使うが、多種多様なフォーマット指定子があるので、ここでまとめたいと思う。本記事では、Go言語の主要なフォーマット指定子とその使い方について解説します。

### 一般的なフォーマット指定子
-  `%v`

汎用のフォーマット指定子で、変数のデフォルト形式で値を出力します。`%v`は、多くの型（プリミティブ型や構造体など）に対して適用できるため、デバッグなどの際に非常に便利です。構造体の場合、フィールド名とその値が表示されます。
```go
type Person struct {
	Name string
	Age  int
}

p := Person{"Alice", 30}
fmt.Printf("%v\n", p)          // 出力: {Alice 30}
fmt.Printf("%v\n", 42)         // 出力: 42
fmt.Printf("%v\n", 3.14159)    // 出力: 3.14159
fmt.Printf("%v\n", true)       // 出力: true
fmt.Printf("%v\n", [2]int{1, 2}) // 出力: [1 2]
```
上記の例では、`%v`を使ってさまざまな型の変数をデフォルトの形式で表示しています。`%v`は、構造体の場合に特に有用で、フィールド名とその値が表示されるため、データの内容を一目で確認することができます。

-  `%+v`
`%v`と同様にデフォルト形式で値を出力するフォーマット指定子ですが、構造体のフィールド名も表示される点が異なります。これにより、構造体内のデータをより明確に把握することができます。
```go
type Person struct {
	Name string
	Age  int
}

p := Person{"Alice", 30}
fmt.Printf("%+v\n", p) // 出力: {Name:Alice Age:30}

type Address struct {
	Street string
	City   string
}

a := Address{"Main St", "San Francisco"}
fmt.Printf("%+v\n", a) // 出力: {Street:Main St City:San Francisco}
```
上記の例では、`%+v`を使って2つの異なる構造体を表示しています。`%+v`により、構造体内のフィールド名とその値が表示されるため、データの内容がより明確になります。

`%+v`は、デバッグやログ出力の際に特に役立ちます。構造体内のデータを確認する必要がある場合や、データの構造を明確に把握したい場合には、`%+v`を使用して情報を表示することができます。これにより、問題の特定やデータの解析が容易になります。

-  `%#v`
構文で表示するフォーマット指定子です。これにより、変数の値を、その型とフィールド名を含むGo言語の表現形式で出力することができます。これは、デバッグやログ出力で特に役立ちます。

```go
type Person struct {
	Name string
	Age  int
}

p := Person{"Alice", 30}
fmt.Printf("%#v\n", p) // 出力: main.Person{Name:"Alice", Age:30}

i := 42
fmt.Printf("%#v\n", i) // 出力: int(42)

f := 3.14159
fmt.Printf("%#v\n", f) // 出力: float64(3.14159)

s := "hello"
fmt.Printf("%#v\n", s) // 出力: "hello"

sl := []int{1, 2, 3}
fmt.Printf("%#v\n", sl) // 出力: []int{1, 2, 3}
```

構造体の場合には、型名、フィールド名、および値が表示されます。他の型についても、型名と値が表示されることがわかります。
データの型や構造を明確に把握したい場合や、デバッグやログ出力で詳細な情報が必要な場合に使用すると効果的です。また、出力結果はGo言語の構文に従っているため、コード内でそのまま使用することができます。

-  `%T`
値の型を表示するフォーマット指定子です。これにより、変数の型名を出力することができます。これは、デバッグやログ出力で型の情報が必要な場合に特に役立ちます。
```go
type Person struct {
	Name string
	Age  int
}

p := Person{"Alice", 30}
fmt.Printf("%T\n", p) // 出力: main.Person

i := 42
fmt.Printf("%T\n", i) // 出力: int

f := 3.14159
fmt.Printf("%T\n", f) // 出力: float64

s := "hello"
fmt.Printf("%T\n", s) // 出力: string

sl := []int{1, 2, 3}
fmt.Printf("%T\n", sl) // 出力: []int

mp := map[string]int{"one": 1, "two": 2}
fmt.Printf("%T\n", mp) // 出力: map[string]int
```
上記の例では、`%T`を使ってさまざまな型の変数の型名を表示しています。これにより、データの型を確認できます。

`%T`は、デバッグやログ出力で、型の情報が必要な場合や、プログラムの動的な挙動を調べたい場合に役立ちます。また、特にインターフェース型の変数を扱う際には、実際にどの型が格納されているかを確認するのに有用です。

-  `%d`
整数を10進数で表示します。
```go
fmt.Printf("%b\n", 9) // 出力: 1001
```

- `%x`、`%X`
整数を16進数で表示します。`%X`は大文字を使用します。
```go
fmt.Printf("%x\n", 255) // 出力: ff
fmt.Printf("%X\n", 255) // 出力: FF
```

- `%f`、`%F`
浮動小数点数を10進数表記で表示するために使用されるフォーマット指定子です。これらの指定子によって、浮動小数点数が小数点以下6桁（デフォルト精度）の精度で表示されます。
```go
fmt.Printf("%f\n", 3.14159)    // 出力: 3.141590
fmt.Printf("%F\n", 3.14159)    // 出力: 3.141590
fmt.Printf("%.2f\n", 3.14159)  // 出力: 3.14
fmt.Printf("%9.4f\n", 3.14159) // 出力: "   3.1416" (最小幅9で表示)
```
上記の例では、`%f`と`%F`は同じ出力結果（3.141590）を生成しますが、精度や表示幅を指定することで、異なる出力形式を作成することができます。例えば、%.2fでは、小数点以下2桁の精度で表示されます（3.14）。`%9.4f`では、最小幅9で表示され、小数点以下は4桁の精度で表示されます（3.1416）。


- `%g`、 `%G`
浮動小数点数を簡潔な形式で表示するためのフォーマット指定子です。これらの指定子は、小数表記と指数表記のうち、短い方を選択して表示します。また、`%g`は小文字の指数（`e`）を使用し、%Gは大文字の指数（`E`）を使用します。
```go
fmt.Printf("%g\n", 0.000314159)     // 出力: 3.14159e-04
fmt.Printf("%G\n", 0.000314159)     // 出力: 3.14159E-04
fmt.Printf("%g\n", 314159.0)        // 出力: 314159
fmt.Printf("%g\n", 3.14159e8)       // 出力: 3.14159e+08
fmt.Printf("%G\n", 3.14159e8)       // 出力: 3.14159E+08
fmt.Printf("%.2g\n", 0.000314159)   // 出力: 3.1e-04
fmt.Printf("%.2G\n", 0.000314159)   // 出力: 3.1E-04
```
上記の例では、`%g`と`%G`が、適切な表記法（小数表記または指数表記）で数値を表示しています。また、精度を指定して、表示形式を制御することができます。

このように、`%g`と`%G`を使って、浮動小数点数を簡潔かつ適切な形式で表示することができます。これらの指定子は、表示スペースを節約したり、可読性を向上させたりする際に役立ちます。

- `%s`
文字列を表示するためのフォーマット指定子です。文字列以外の値の場合、その値が`fmt.Stringer`インターフェースを実装していると、`String()`メソッドの結果が表示されます。
```go
type Stringer interface {
	String() string
}

type Greeting string

func (g Greeting) String() string {
	return string(g) + "!"
}

hello := Greeting("Hello")
fmt.Printf("%s\n", hello) // 出力: Hello!

name := "Alice"
fmt.Printf("%s\n", name) // 出力: Alice

i := 42
fmt.Printf("%s\n", strconv.Itoa(i)) // 出力: 42
```

- `%q`
引用符で囲まれた文字列を表示するためのフォーマット指定子です。これにより、文字列をそのままの形式で安全に表示できます。これは、文字列内に特殊文字やエスケープシーケンスが含まれている場合に特に役立ちます。
```go
s := "hello"
fmt.Printf("%q\n", s) // 出力: "hello"

s2 := "こんにちは"
fmt.Printf("%q\n", s2) // 出力: "こんにちは"

s3 := `hello
world`
fmt.Printf("%q\n", s3) // 出力: "hello\nworld"

s4 := "hello\tworld"
fmt.Printf("%q\n", s4) // 出力: "hello\tworld"

s5 := "\"hello\""
fmt.Printf("%q\n", s5) // 出力: "\"hello\""

```
`%q`を使ってさまざまな文字列を引用符で囲んで表示しています。改行文字やタブ文字などのエスケープシーケンスも正しく表示されることがわかります。
`%q`は、文字列の中に特殊文字やエスケープシーケンスが含まれている場合、または文字列をそのままの形式で表示する必要がある場合に使用します。デバッグやログ出力で、文字列の中身を明確に確認したい場合に役立ちます。

- `%p`
ポインタのアドレスを表示します。
```go
num := 42
ptr := &num
fmt.Printf("%p\n", ptr) // 出力: 0xc0000120b0 (アドレスは実行ごとに異なります)
```

- `%c`
Unicode文字として表示します。整数に対応する文字を表示します。
```go
fmt.Printf("%c\n", 65) // 出力: A
```

- `%e`、`%E`
指数表現の浮動小数点数を表示します。`%E`は大文字の指数（`E`）を使用します。
```go
fmt.Printf("%e\n", 1234.5678) // 出力: 1.234568e+03
fmt.Printf("%E\n", 1234.5678) // 出力: 1.234568E+03
```

- `%o`
整数を8進数で表示します。
```go
fmt.Printf("%o\n", 9) // 出力: 11
```

- `%u`
符号なしの整数を10進数で表示します。
```go
fmt.Printf("%u\n", -10) // 出力: 18446744073709551606 (uint64型として解釈)
```

### 表示幅と精度のオプション

- `%[幅]d`
最小幅を指定して整数を10進数で表示します。
```go
fmt.Printf("%6d\n", 42) // 出力: "    42"（最小幅6、右寄せ）
```

- `%.[精度]f`
精度を指定して浮動小数点数を表示します。
```go
fmt.Printf("%.2f\n", 3.14159) // 出力: 3.14（小数点以下2桁）
```

- `%[幅].[精度]g`
最小幅と精度を指定して浮動小数点数を表示します。
```go
fmt.Printf("%5.2f\n", 3.14159) // 出力: " 3.14"（最小幅5、小数点以下2桁）
```

これらのフォーマット指定子とオプションを使いこなすことで、さまざまな出力形式を簡単に実現できます。Go言語の`fmt`パッケージは非常に強力で柔軟性が高いため、プログラムの出力やデバッグの際に役立ちます。以下に、これらの指定子とオプションの使用例をいくつか提示してみます。

```go
type Person struct {
	FirstName string
	LastName  string
	Age       int
}

func (p Person) String() string {
	return fmt.Sprintf("%s %s, age %d", p.FirstName, p.LastName, p.Age)
}

p := Person{"Alice", "Smith", 30}

fmt.Printf("Person with %%s: %s\n", p)                // 出力: Person with %s: Alice Smith, age 30
fmt.Printf("Person with %%q: %q\n", p)                // 出力: Person with %q: "Alice Smith, age 30"
fmt.Printf("Float with %%f: %f\n", 3.14159265359)     // 出力: Float with %f: 3.141593
fmt.Printf("Float with %%.3f: %.3f\n", 3.14159265359) // 出力: Float with %.3f: 3.142
fmt.Printf("Hex with %%x: %x\n", 16)                  // 出力: Hex with %x: 10
fmt.Printf("Octal with %%o: %o\n", 10)                // 出力: Octal with %o: 12
fmt.Printf("Unicode with %%c: %c\n", 65)              // 出力: Unicode with %c: A
```

### `nil`の場合
Go言語では、`nil`はゼロ値として扱われます。`nil`はポインタ、スライス、マップ、チャネル、関数、インターフェース型の変数に対してゼロ値として設定されます。`nil`が含まれる変数の挙動は、その型とコンテキストによって異なります。

`fmt.Printf`で`nil`が含まれる変数を表示する際の挙動は、フォーマット指定子に依存します。以下に、いくつかのフォーマット指定子を使用した場合のnilの表示例を提示してみます。

```go
var ptr *int
var slc []int
var mp map[string]int
var fn func()

fmt.Printf("%v\n", ptr) // 出力: <nil>
fmt.Printf("%v\n", slc) // 出力: []
fmt.Printf("%v\n", mp)  // 出力: map[]
fmt.Printf("%v\n", fn)  // 出力: <nil>
```

`%v`や`%+v`を使って`nil`を表示すると、`<nil>`として出力されます。ただし、スライスやマップの場合は、それぞれ`[]`および`map[]`と表示されます。

`nil`が入った変数を操作しようとすると、実行時にエラーが発生することがあります。例えば、`nil`のマップにキーを追加しようとすると、実行時に`panic`が発生します。そのため、`nil`を含む変数を使用する前に、変数が`nil`でないことを確認することが重要です。

```go
var mp map[string]int

if mp == nil {
    fmt.Println("map is nil")
} else {
    mp["key"] = 42 // これはpanicを引き起こします。
}
```

このように、`nil`が含まれる変数の挙動は、型とコンテキストによって異なります。また、`nil`を含む変数を操作する際には、エラーが発生しないよう注意が必要です。

この記事で紹介したフォーマット指定子とオプションは、Go言語の`fmt`パッケージの基本的な機能をカバーしています。これらを駆使することで、さまざまな出力形式を容易に実現できます。

詳細な情報や他のフォーマット指定子については、公式ドキュメントを参照してください。
この記事が、Go言語での出力やデバッグ作業をより効率的に行う手助けとなると嬉しいです。

https://pkg.go.dev/fmt

https://go.dev/ref/spec

https://programing-school.work/golang-about-nil/