こんにちは、ナナオです。
map
package main
import "fmt"
func main() {
// このmapはnilのため、make関数で初期化する必要がある
var m map[string]int
// make関数でmapを作成する
m = make(map[string]int)
// このマップは初期化済み
m = map[string]int{
"A": 1,
"B": 2,
}
// キーの追加
m["Answer"] = 42
fmt.Println("The value:", m["Answer"])
// キーの変更
m["Answer"] = 48
fmt.Println("The value:", m["Answer"])
// キーの削除
delete(m, "Answer")
fmt.Println("The value:", m["Answer"])
// キーの取得と存在確認
v, ok := m["Answer"]
fmt.Println("The value:", v, "Present?", ok)
}
関数
関数も変数として定義することができますし、引数にもできます。
package main
import (
"fmt"
"math"
)
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(5, 12))
fmt.Println(compute(hypot))
fmt.Println(compute(math.Pow))
}
メソッド
メソッドはレシーバ引数を実装することで可能です。
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := Vertex{3, 4}
fmt.Println(v.Abs())
}
インターフェース
インターフェースは以下のように実装します。
インターフェースのレシーバ引数のポインタはメソッドと違って厳密に判定されます。
例えば以下の例ではI型のインターフェースを実装したMメソッドのレシーバ引数を*Tとするとエラーになります。
その場合エラーを解消するにはレシーバ引数をTに戻すか、もしくは呼び出し方を&T{"hello"}に変更すればエラーは解消します。
package main
import "fmt"
type I interface {
M()
}
type T struct {
S string
}
// This method means type T implements the interface I,
// but we don't need to explicitly declare that it does so.
func (t T) M() {
fmt.Println(t.S)
}
func main() {
var i I = T{"hello"}
i.M()
}
また、インターフェースに定義したメソッドのレシーバ引数はnilである場合があります。(これは結構引っ掛かりそうな仕様。。)
package main
import "fmt"
type I interface {
M()
}
type T struct {
S string
}
func (t *T) M() {
if t == nil {
fmt.Println("<nil>")
return
}
fmt.Println(t.S)
}
func main() {
var i I
var t *T
i = t
describe(i)
// 出力は<nil>
i.M()
}
更にgoには空のインターフェースというのが存在します。
(これはPythonのAny型とかTypeScriptのany型みたいなこと…?)
package main
import "fmt"
func main() {
var i interface{}
describe(i)
i = 42
describe(i)
i = "hello"
describe(i)
}
func describe(i interface{}) {
fmt.Printf("(%v, %T)\n", i, i)
}
空インターフェースを利用して型switchなどの仕組みを実現できます。
package main
import "fmt"
func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Twice %v is %v\n", v, v*2)
case string:
fmt.Printf("%q is %v bytes long\n", v, len(v))
default:
fmt.Printf("I don't know about type %T!\n", v)
}
}
func main() {
do(21)
do("hello")
do(true)
}
まとめ
今日はここまでにします。
go、奥深い。