Golang Cafe #7 まとめ 1.2での変更ほか
2013/12/08に開催された「Golang Cafe #7」についてのまとめです。
今回は14日(土)の合同勉強会 in 大都会岡山 -2013 Winter-でセッションデビューする+Ryuji Iwata氏の練習と、余った時間で1.2で追加・変更になった機能からのピックアップと、私が気になった部分を+TakashiYokoyama氏に質問するだけで時間が一杯となりました。
+Ryuji Iwata氏の発表内容については勉強会後公開されると思いますので、ここでは触れないでおきます。
私が質問したこと
C#でいうところのdecimal型の扱い
C#では値型としてdecimal型が用意されています。
「財務や金融の計算に適しています」とリンク先にも書かれている通りで、お金関係の計算で丸め誤差を無視できない場合に使用しています。(適当な有効桁で端数処理すればいいだろという話はおいておいて)
ただ実行速度は遅くなってしまうのでそこはトレードオフです。
Go言語でdecimalに相当するものは無いのかというと、無いそうです。JavaのBigInteger、BigDecimalに相当するmath/big/Int、math/big/Ratを使用するしかなさそうです。さらにはJavaとはお作法が少し違うようなので注意も必要です。
package main import ( "fmt" "math/big" ) func main() { i, j, k := big.NewInt(1), big.NewInt(2), big.NewInt(0) x := i.Add(i, j) k.Add(i, j) fmt.Println(i, j, k, x) }
3 2 5 3
値の型名の取得
今まではswitch文で判定するかreflectパッケージを使用するかしかなかったようですが、1.2になって別の方法が増えたようです。
switch文での判定、reflectパッケージの使用、およびPrintf("%T", ...)を使用することで取得できます。
後述のThe fmt packageでも書きます。
package main import ( "fmt" "reflect" ) func main() { var i int32 = 1 // reflectパッケージを使った方法 typeName1 := reflect.ValueOf(i).Type().Name() // 1.2での追加 typeName2 := fmt.Sprintf("%T", i) fmt.Println(typeName1, typeName2) }
int32 int32
1.2で追加・変更になった機能からピックアップ
先日1.2が正式に発表になりました、詳細はGo 1.2 Release Notesで。
今回は+TakashiYokoyama氏が何点かピックアップしてくれました。
Use of nil
当日説明を聞いただけではよく分からなかったのですが、Go 1.2 Nil Checksの内容を実際に1.1と1.2での結果を比較してみた分かりました。
検証に使用したコードは以下のものでリンク先にあるとおりです。
package main import ( "fmt" ) type T struct { Field1 int32 Field2 int32 } type T2 struct { X [1<<24]byte Field int32 } func main() { var x *T p1 := &x.Field1 p2 := &x.Field2 var x2 *T2 p3 := &x2.Field fmt.Println(p1, p2, p3) }
1.1.2で実行した場合の結果は以下のとおりです。
panic: runtime error: invalid memory address or nil pointer dereference [signal 0xc0000005 code=0x0 addr=0x0 pc=0x401030] goroutine 1 [running]: main.main() d:/study/golang/src/practice/sample.go:22 +0x30 goroutine 2 [runnable]: exit status 2
1.2で実行した場合の結果は以下のとおりです。
panic: runtime error: invalid memory address or nil pointer dereference [signal 0xc0000005 code=0x1 addr=0x0 pc=0x4010ee] goroutine 1 [running]: runtime.panic(0x4a7760, 0x58536f) C:/Users/ADMINI~1/AppData/Local/Temp/2/bindist667667715/go/src/pkg/runtime/panic.c:266 +0xc8 main.main() d:/study/golang/src/practice/sample.go:19 +0xee exit status 2
両方ともpanicが起こっていますが、発生している箇所が違います。
今までは初期化していない構造体のポインタのフィールドにアクセスできていましたが、1.2になってこれがpanicになるようになったようです。
Three-index slices
配列からスライスを作成するときに3つ目のインディックスでキャパシティを指定することで、スライスを変更した際に元の配列に影響する範囲を指定することができます。(逆に言うと影響されないようにできる)
package main import "fmt" func main() { m1() fmt.Println() m2() fmt.Println() m3() } func m1() { arr := setup() slice := arr[2:4] appendAndOutput(slice) fmt.Println(arr) } func m2() { arr := setup() slice := arr[2:4:7] appendAndOutput(slice) fmt.Println(arr) } func m3() { arr := setup() slice := arr[2:4:4] appendAndOutput(slice) fmt.Println(arr) } func setup() [10]int { return [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} } func appendAndOutput(slice []int) { fmt.Printf("%v, len=%d, cap=%d\n", slice, len(slice), cap(slice)) for i := 0; i < 10; i++ { slice = append(slice, 100) } fmt.Println(slice) }
[3 4], len=2, cap=8 [3 4 100 100 100 100 100 100 100 100 100 100] [1 2 3 4 100 100 100 100 100 100] [3 4], len=2, cap=5 [3 4 100 100 100 100 100 100 100 100 100 100] [1 2 3 4 100 100 100 8 9 10] [3 4], len=2, cap=2 [3 4 100 100 100 100 100 100 100 100 100 100] [1 2 3 4 5 6 7 8 9 10]
The fmt package
fmtパッケージのPrintfメソッドでのフォーマットの指定方法が追加されました。
一つは先ほどの「私が質問したこと」のところでも少し書きましたが、%Tを指定することで型を表示できるようになりました。
もう一つはフォーマット文字列内で値のインディックスが指定できるようになりました。
ただ気をつけなくてはならないのは、インディックスを指定したした後にインディックスを指定しないものがあると直前のインディックス+1と解釈されるということです。
バグを生み出さないためにもどちらかだけで統一したほうがいいかもしれません。
package main import "fmt" func main() { // // 1.1.2でもこの方法は可能だったようです。 //v := 1.0 //fmt.Printf("%T\n", v) // v1, v2, v3, v4, v5 := "あ", "い", "う", "え", "お" fmt.Printf("%v, %v, %v, %v, %v\n", v1, v2, v3, v4, v5) fmt.Printf("%[5]v, %[5]v, %[3]v, %[3]v, %[1]v\n", v1, v2, v3, v4, v5) fmt.Printf("%[2]v, %v, %[1]v, %v, %v\n", v1, v2, v3, v4, v5) }
float64 あ, い, う, え, お お, お, う, う, あ い, う, あ, い, う
最後に
次回は「今年のGo言語の振り返りと、来年のGo言語の動向」がテーマだそうです。
2013/12/14追記
1.2の機能でTest coverageが気になったのを忘れていました。
一度確かめておかなくてはなりませんね。