Golang Cafe #2 まとめ

2013/11/03に開催された「Golang Cafe #2」についてのまとめです。
今回の内容は大きく分けて2つありました。
1つ目は前回はっきりしなかったtestingパッケージのExampleについての補足、もうひとつはencoding/jsonパッケージのソースコードリーディングです。
これらについてまとめておきたいと思います。

testingパッケージのExampleについての補足

私の個人的か見解については前回まとめさせていただいた内容のとおりです。
大筋では間違いはないように思えました。
Pythonではdoctestという似たような機能があると+Ryuji Iwata氏やGoogle+の方で教えていただきました。


ではここで書いたExampleコードがどのように利用されるのかが気になります。
Go言語に関する書籍も出版されている+TakashiYokoyama氏によればgo docした際に出力されるのではとのこと。
先週のサンプルで試してみると、

$ go doc sample.com/mylib1
PACKAGE DOCUMENTATION

package mylib1
    import "sample.com/mylib1"



FUNCTIONS

func Div(x int, y int) float64
    x / y の計算を行います。

コマンドライン上でなんとなく出力されましたがイマイチな感じです。
できれば後日検証して別エントリーにまとめてみます。
こちらにまとめておきました。

encoding/jsonパッケージ リーディング

encoding/jsonパッケージを読んでいきます。
reflectパッケージ等も一部読みましたが、今回の対象ではないので割愛します。

今回対象のソースコードはencoding/json/encode.goになります。
まとめ方が難しいですが、ソースコードを追いかけた順にまとめておきます。

  1. 入り口はMarshal関数、引数はv interface{}を取り、戻り値はbyte配列とerrorになります。
  2. encodeState型の変数を定義しvを引数にmarshalメソッドを呼びます。
  3. defer文にて遅延実行するエラー処理を定義します。
  4. reflect.ValueOf(v)にてValueにラップされた値を引数にreflectValueメソッドを呼びます。
  5. v reflect.Valueとfalseを引数にreflectValueQuotedメソッドを呼びます。
  6. vが有効でなければnullを出力します。
  7. vがMarshaler型でない場合、ポインタで参照先のアドレスが有効であれば参照先の値の型を確認しMarshaler型であればその値をvとして使用します。
  8. 最終的にvがMarshaler型でポインタではなく、nilでもない場合、MarshalJSONメソッドを呼び処理は終了です。
  9. vがMarshaler型でない場合は以下のようにv.Kind()の値によって処理を分けます。
    • Bool型の場合はtrueまたはfalseを出力して終了します。
    • IntXXX型の場合は10を基数とする整数を出力して終了します。
    • UintXXX型の場合は10を基数とする符号なし整数を出力して終了します。
    • FloatXXX型の場合、無効な数値の場合はエラーとし、有効な場合はgフォーマット出力して終了します。
    • String型の場合は値が数値で""の場合は0を出力、quoted=trueの場合はMarshal型にして出力、それ以外の場合は文字列を出力します。
    • Struct型の場合は{}で囲み、フィールド:値の形でカンマ区切りで出力します。値はreflectValueQuotedを呼び再帰的に処理します。
    • Map型の場合キーがString型でない場合はエラー、{}で囲み、キー:値の形でカンマ区切りで出力します。値はreflectValueを呼び再帰的に処理します。
    • Slice型の場合、要素がUint8型の場合""で囲み、サイズが1024未満のときは最小サイズに、そうでない場合はそのままのサイズでBase64エンコードして出力します。要素がUint8型以外の場合はArray型の処理に流します。
    • Array型の場合は[]で囲み各要素をカンマ区切りで出力します。値はreflectValueを呼び再帰的に処理します。
    • Interface型、Ptr型の場合は要素を引数にreflectValue関数を呼びます。
    • それ以外の場合はエラーとします。

今日学んだ文法

  • interface{}というのは他の言語で言うobjectのイメージ。何でもよし。
  • 関数では複数の戻り値を扱うことができます。
  • deferは関数が終了した後に実行される処理を定義します。
  • try-finallyに近いイメージですが、return直前に実行されるのではなくreturn後に実行されるようです。
  • deferは複数定義することができ、最後に定義されたものから順次実行されます。
  • 浮動小数虚数のフォーマット文字列 fmtパッケージ