プログラミング言語 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

インターフェース。

静的型付け+ダックタイピング という感じで面白い。

代入の方チェック

go
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 の比較

比較できたり、比較しようとしたらパニックになったりする。ややこわい。

go
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 であるもの

なんか罠らしい。

go
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

なんか使いにくい気がするこれ。

go
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++ でいうところのキャストは、「型アサーション」。

go
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のキャストと異なり、失敗するとパニックになる。

go
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)
}

しかし、第二引数がある場合にはパニックにならない。

go
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章のおわり

もっと書きたいことがあるんだけど、この章はちゃんと設計していないとなかなか良さも悪さもわからない。
先に進もうと思う。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.