Slide 1

Slide 1 text

The Go gopher was designed by Renée French. The gopher stickers was made by Takuya Ueda. Licensed under the Creative Commons 3.0 Attributions license. fmfm🤔 fmtパッケージ 2022年03月05日(金) 資料:https://tenn.in/fmt

Slide 2

Slide 2 text

上田拓也 Go ビギナーズ
 Go Conference
 @tenntenn tenntenn.dev Google Developer Expert (Go) 一般社団法人 Gophers Japan 代表理事 Experts Team

Slide 3

Slide 3 text

fmtパッケージとは? ■ 書式に関する処理をまとめたパッケージ ● https://pkg.go.dev/fmt ● Print系の関数:表示を行う関数 ○ F◯◯系:出力先をio.Writerインタフェースとして指定できる ○ S◯◯系:文字列として出力する ○ ◯◯f系:出力の書式を指定できる ○ ◯◯ln系:末尾に改行をつける ● Scan系の関数:入力を行う関数 ○ F◯◯系:入力元をio.Readerインタフェースとして指定できる ○ S◯◯系:文字列から入力を得る ○ ◯◯f系:入力の書式を指定できる ○ ◯◯ln系:改行区切りで入力を受け付ける

Slide 4

Slide 4 text

便利なverb ■ 書式を指定する文字(rune型) ● 指定する値の型によって挙動は変わる ● 基本はCのprintf関数のverbに良く似ている verb 意味 使い方 v その型のデフォルトの書式を用いる fmt.Printf("%v", "hoge") // hoge q 文字や文字列をクォートで囲む fmt.Printf("%q", "hoge") // "hoge" T Goの型を表す fmt.Printf("%T", "hoge") // string p ポインタ fmt.Printf("%p", &x)

Slide 5

Slide 5 text

書式のフラグ ■ 書式に付加情報を指定する ● 無効なフラグを指定すると無視される ● int型で表される(rune型ではない) flag 意味 使い方 + 数値の場合は必ず+符号をつける。構造体の 場合はフィールド名をつける fmt.Printf("%v", "hoge") // hoge - 左詰め fmt.Printf("%-2d@", 1) // 1 @ # その書式のより詳しい形式。 %#vはGoの構文 上の表現になる fmt.Printf("%#v", []int{1}) // []int{1} ' ' 空白。%dは省略された符号のためのスペー ス fmt.Printf("% d", 100) // 100 0 ゼロ埋めする fmt.Printf("%02d", 1) // 01

Slide 6

Slide 6 text

幅と精度 ■ 幅(width)はverbの前に数値で記述 ■ 精度(precision)は幅の後ろの.に数値で記述 書式 幅 精度 %f デフォルト デフォルト %9f 9 デフォルト %.2f デフォルト 2 %9.2f 9 2 %9.f 9 0 fmt.Printf("%9.2f", 12.345) // 12.35

Slide 7

Slide 7 text

インデックスを指定して書式を適用 ■ verbの前に[n]を指定する ● 関数のn番目の引数に対して書式を指定する ● 同じ値に複数の書式を指定したい場合に用いると便利 fmt.Printf("%[2]d %[1]d\n", 10, 20) // 20 10 fmt.Printf("%[1]v %[1]T\n", 10) // 10 int

Slide 8

Slide 8 text

文字列のクォート ■ %qを指定する ● %#qはstrconv.CanBackquote関数がtrueを返す場合は``で括る ● strconv.Quote関数でもOK ● 逆をやりたい場合はstrconv.Unquote関数を用いる fmt.Printf("%q\n", "hoge") // "hoge" fmt.Printf("%#q %#q\n", "hoge", "`hoge`") // `hoge` "`hoge`" s := strconv.Quote(`"hoge"`) fmt.Println(s) // "\"hoge\"" fmt.Println(strconv.Unquote(s)) // "hoge"

Slide 9

Slide 9 text

fmtパッケージのインタフェース ■ Print系のインタフェース ● Stringerインタフェース ● GoStringerインタフェース ● Formatterインタフェース ● Stateインタフェース ■ Scan系のインタフェース ● Scannerインタフェース ● ScanStateインタフェース

Slide 10

Slide 10 text

fmt.Stringerインタフェース ■ その型のネイティブなフォーマットを定義する ● 書式を指定しないPrint系の関数で呼ばれる ○ Printf系でも%sなどの書式を指定すると呼ばれる type Stringer interface { String() string }

Slide 11

Slide 11 text

fmt.GoStringerインタフェース ■ 書式で%#vを指定された場合の文字列を返す type GoStringer interface { GoString() string }

Slide 12

Slide 12 text

fmt.Formatterインタフェース ■ 書式に対する振る舞いを定義するインタフェース ● verbやフラグ、精度、幅などを自由に定義できる ● verbはrune型で表される ● 文字列の書き込みやフラグ、精度、幅はStateインタフェースが担当 type Formatter interface { Format(f State, verb rune) } 参考:fmt.Formatterを実装して%vや%+vをカスタマイズしたり、 %3🍺みたいな書式をつくってみよう

Slide 13

Slide 13 text

fmt.Stateインタフェース ■ 1つのverbに対する処理を記述する ● 幅、精度、フラグが取得できる ○ すべてint型で表される ● Writeメソッドを使って書き込む ○ Fprint系の関数にも対応 type State interface { // フォーマットした結果を書き込む Write(b []byte) (n int, err error) // 幅を取得、設定されていない場合は okがfalse Width() (wid int, ok bool) // 精度を取得、設定されていない場合は okがfalse Precision() (prec int, ok bool) // フラグが指定されているか取得 Flag(c int) bool }

Slide 14

Slide 14 text

fmt.Scannerインタフェース ■ Scan系の書式の振る舞いを記述する ● fmt.Scan関数やfmt.Scanln関数の場合はverbはvになる type Scanner interface { Scan(state ScanState, verb rune) error }

Slide 15

Slide 15 text

fmt.ScanStateインタフェース ■ トークンごとに読み込みを行う ● 幅なども取れる type ScanState interface { // 1コードポイントを読み込む ReadRune() (r rune, size int, err error) // 次のReadRuneでも同じ結果が返ってくるようにする UnreadRune() error // 空白を飛ばす SkipSpace() // skipSpaceがtrueの場合は空白を飛ばす。 fがtrueを返す間読み込む Token(skipSpace bool, f func(rune) bool) (token []byte, err error) // 幅を取得、設定されていない場合は okがfalse Width() (wid int, ok bool) // ReadRuneがあるため常にエラーを返すように実装する Read(buf []byte) (n int, err error) }

Slide 16

Slide 16 text

fmt.Errorf関数で作られるエラー ■ ラップしない場合 ● 書式を指定してエラーを作成 ● errors.New関数では作成できない複雑なエラーメッセージのエラー ■ ラップする場合 ● %wを指定する ● 引数で指定したエラーをラップしてエラーを作る ● Unwrapメソッドを実装したエラーが作られる ● errors.Unwrap関数で元のエラーが取得できる err := fmt.Errorf("%s is not found", name) err := fmt.Errorf("bar: %w", errors.New("foo")) fmt.Println(err) // bar: foo fmt.Println(errors.Unwrap(err)) // foo

Slide 17

Slide 17 text

まとめ ■ 案外知らないことが多い ● パッケージドキュメントを読みましょう ■ インタフェースを上手く使おう ● StringメソッドとGoStringメソッドを使い分ける ● Formatterインタフェースを実装する