プログラミング言語 Go を読みながらメモ。
第一章 : https://qiita.com/Nabetani/items/077c6b4d3d1ce0a2c3fd
第二章 : https://qiita.com/Nabetani/items/d053304698dfa3601116
第三章 : https://qiita.com/Nabetani/items/2fd9c372fcd8383955a5
第四章 : https://qiita.com/Nabetani/items/59bfd00dc3323883a07f
第五章 : https://qiita.com/Nabetani/items/4b785f1c9b0b26d48475
第六章 : https://qiita.com/Nabetani/items/1c100394a65af6506187
で
インターフェース。
静的型付け+ダックタイピング という感じで面白い。
代入の方チェック
package main
import "fmt"
type Foo struct{}
func (f Foo) Bar() {}
func (f Foo) Baz() {}
type Bar interface {
Bar()
}
type BarBaz interface {
Bar
Baz()
}
func main() {
foo := Foo{}
var bar Bar = foo // okay
var barbaz1 BarBaz = foo // okay
var barbaz2 BarBaz = bar // cannot use bar (type Bar) as type BarBaz in assignment:
fmt.Println(foo, bar, barbaz1, barbaz2)
}
この通り、bar
の正体が foo
であっても、型チェックは静的に行われるのでエラーになる。
たぶん、無理矢理キャストする方法がこの後出てくると思うんだけど、これを書いている時点ではまだそこまで読み進めていない。
interface の比較
比較できたり、比較しようとしたらパニックになったりする。ややこわい。
package main
import "fmt"
func main() {
var x interface{} = [3]int{1, 2, 3}
fmt.Println(x == x) // okay, true.
var y interface{} = []int{1, 2, 3}
fmt.Println(y == y) // panic: runtime error: comparing uncomparable type []int
}
nil っぽいものと nil であるもの
なんか罠らしい。
package main
import (
"bytes"
"fmt"
"io"
)
func main() {
var buf *bytes.Buffer
fmt.Println(buf, buf == nil) //=> <nil> true
var out1 io.Writer
fmt.Println(out1, out1 == nil) //=> <nil> true
var out2 io.Writer = buf
fmt.Println(out2, out2 == nil) //=> <nil> false
}
なるほど罠だ。
sort
なんか使いにくい気がするこれ。
package main
import (
"fmt"
"sort"
)
type StringSlice []string
func (s StringSlice) Len() int {
return len(s)
}
func (s StringSlice) Less(i, j int) bool {
// 二文字目で比較
return s[i][1] < s[j][1]
}
func (s StringSlice) Swap(i, j int) {
tmp := s[i]
s[i] = s[j]
s[j] = tmp
}
func main() {
var strs StringSlice = []string{"oh", "be", "afine", "girl", "kiss", "me", "right", "now"}
sort.Sort(strs)
fmt.Println(strs) //=> [be me afine oh girl kiss right now]
}
「n 文字目で整列」のようなものを書く方法がわからない。
型アサーション
C/C++ でいうところのキャストは、「型アサーション」。
package main
import "fmt"
type Foo struct{}
func (f Foo) Bar() {}
func (f Foo) Baz() {}
type Bar interface {
Bar()
}
type BarBaz interface {
Bar
Baz()
}
func main() {
foo := Foo{}
var bar Bar = foo // okay
var barbaz1 BarBaz = foo // okay
var barbaz2 BarBaz = bar.(BarBaz) // 「型アサーション」が必要
fmt.Println(foo, bar, barbaz1, barbaz2)
}
型アサーションは、Cのキャストと異なり、失敗するとパニックになる。
package main
import "fmt"
type Hoge struct{}
type Fuga struct{}
func (f Fuga) Bar() {}
func (h Hoge) Bar() {}
func (h Hoge) Baz() {}
type Bar interface {
Bar()
}
type BarBaz interface {
Bar
Baz()
}
func main() {
var hoge Bar = Hoge{} // okay
var fuga Bar = Fuga{}
var hoge2 BarBaz = hoge.(BarBaz) // okay, hoge can be BarBaz
var fuga2 BarBaz = fuga.(BarBaz) // panic: interface conversion: main.Fuga is not main.BarBaz: missing method Baz
fmt.Println(hoge, fuga, hoge2, fuga2)
}
しかし、第二引数がある場合にはパニックにならない。
package main
import "fmt"
type Hoge struct{}
type Fuga struct{}
func (f Fuga) Bar() {}
func (h Hoge) Bar() {}
func (h Hoge) Baz() {}
type Bar interface {
Bar()
}
type BarBaz interface {
Bar
Baz()
}
func main() {
var hoge Bar = Hoge{} // okay
var fuga Bar = Fuga{}
hoge2, hoge2okay := hoge.(BarBaz) // okay, hoge can be BarBaz
fuga2, fuga2okay := fuga.(BarBaz) // panic: interface conversion: main.Fuga is not main.BarBaz: missing method Baz
fmt.Println(hoge, fuga, hoge2, hoge2okay, fuga2, fuga2okay) //=>{} {} {} true <nil> false
}
この、返戻値の数によって動作が変わるっていうのはどうなんだろうと思った。
まあ気持ちはわかるけれども。
ユーザーがそういう関数を書く方法はあるのだろうか??
7章のおわり
もっと書きたいことがあるんだけど、この章はちゃんと設計していないとなかなか良さも悪さもわからない。
先に進もうと思う。