golang
基本
実行
go run hello.go
実行ファイルは作成されない。
ビルド(コンパイル)
go build hello.go
実行ファイルが作成される。
Go のプログラムは package から始まる。
package を import とすると,公開された(export)名前を参照できる。
export するには,名前を大文字で始めること。小文字で始めると参照できない。
関数
func add(x int, y int) int { return x + y } // 同じ型ならまとめられる func add(x, y int) int { return x + y } // 複数返せる func swap(x, y string) (string, string) { return y, x } func main() { a, b := swap("hello", "world") } // named return values, 短い関数でのみ使ってよい (メリットが分からん) func split(sum int) (x, y int) { x = sum * 4/ 9 y = sum - x return }
デフォルト引数はない
変数宣言
var i int var c, python, java bool var i, j int = 1, 2 var ( s = 3 t = 5 ) k := 3 // 暗黙的な型宣言, 関数の中だけ
初期値を与えずに宣言すると,ゼロ値 (zero value)が与えられる
数値型:0, bool:false, string:""(空文字)
スライスのゼロ値は nil
型変換
T(v) // 変数 v を T 型に変換する, 明示的な変換が必要
定数
const Pi = 3.14 const ( Big = 1 << 100 Small = BIg >> 99 )
character, string, boolean, numeric のみ使える
:= は使えない
定数には型がなく,値として扱われる。その状況によって必要な型を取る。
basic types
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // uint8 の別名
float32 float64
complex64 complex128
制御
// dummy comment for i := 0; i < 10; i++ { } for sum < 1000 { // as while } for { // 無限ループ } if x < 0 { } if v := math.Pow(x, n); v < lim { // init scope is in if and else } // break はない(勝手に提供される) // 上から case を評価して,終わったら break switch os := runtime.GOOS; os { case "darwin": fmt.Println("OS X.") case "linux": fmt.Println("Linux.") default: fmt.Println("%s.", os) } switch { // as `switch true`. works as if-then-else case t.Hour < 12: fmt.Println("Good morning!") case t.Hour < 17: fmt.Println("Good afternoon.") default: fmt.Println("Good evening.") } func main() { file, err = os.Open("path/to/file") defer file.Close() } // defer は引数の評価は即時。実行は関数終了後。スタック順序
ポインタ
// ポインタ演算はない var p *int // ゼロ値は nil i := 42 p = &i *p = 21
データ構造
type Vertex struct { X int Y int // `X, Y int` is also ok. } v := Vertex{1, 2} v.X = 4 p := &v p.X = 1e9 v2 := Vertex{X: 1} // 部分的初期化, 他はゼロ値 v2 := Vertex{} // ゼロ値 初期化 ptr := &Vetrex{1, 2}
配列とスライス
var arr [2]string // 配列の長さは型の一部分。配列サイズは変えれない arr[0] = "Hello" primes := [6]int{2, 3, 5, 7, 11, 13} var s []int = primes[1:4] // size は 3 = 4 - 1, 後ろの index は -1 でアクセスされる fmt.Println(s) // [3 5 7] s[0] = 99 // スライスは配列への参照。primes は [2 99 5 7 11 13] [3]bool{true, true, false} // 配列リテラル []bool{true, true, false} // 上記と同じ配列を作り,そのスライスを作成する // スライスの値は省略できる // スライスには length len() と capacity cap() がある。 // python みたいに -1 とかは使えない s := []string{"a", "b", "c", "d", "e", "f",} s = s[1:4] // b, c, d s = s[:2] // b, c s = s[1:] // c, len(s) = 1, cap(s) = 4 s = s[:4] // capacity まで後ろに拡張できる。前にはできない // make はゼロ化された配列を割り当て,その配列のスライスを返す a := make([]int, 5) // len(a) = 5 b := make([]int, 0, 5) // len(b) = 0, cap(b) = 5 // 2次元配列スライス board := [][]string{ []string{"_", "_", "_"}, []string{"_", "_", "_"}, []string{"_", "_", "_"}, } // append, 返り値を受ける必要がある var s = []int s = append(s, 0) s = append(s, 1, 2, 3, 4, ) func printSlice(s []int) { fmt.Printf("len=%d, cap=%d, %v\n", len(s), cap(s), s) } // range for i, v := range s { fmt.Printf("index %d, value %d\n", i, v) } for i := range s { // index only fmt.Printf("index %d, value %d\n", i, v) } for _, v := range s { // skip index fmt.Printf("index %d, value %d\n", i, v) }
Map
type Vertex struct { Lat, Long float64 } var m_ map[string]Vertex m_["Bell Labs"] = Vertex{40.68433, -74.39967} var m = map[string]Vertex{ "Bell Labs": Vertex{ 40.68433, -74.39967, }, "Google": {37.42202, -122.08408}, // 型を推測できるときは省略できる } delete(m, "Google") v, ok := m["Google"] fmt.Println("The value:", v, "Present?", ok)
func
func compute(fn func(float64, float64) float64) float64 { return fn(3, 4) } hypot := func(x, y float64) float64 { return math.Sqrt(x*x + y*y) } fmt.Println(hypot(5, 12)) fmt.Println(compute(hypot))
closure
package main import "fmt" func adder() func(int) int { sum := 0 return func(x int) int { sum += x return sum } } func main() { pos, neg := adder(), adder() for i := 0; i < 10; i++ { fmt.Println( pos(i), // 0, 1, 3, 6, 10, ... neg(-2*i), // 0, -2, -6, -12, -20, ... ) } }
method
type Vertex truct { X, Y float64 } func (v Vertex) Abs() float64 { // copy instance return math.Sqrt(v.X*v.X + v.Y*v.Y) } func (v *Vertex) Abs() float64 { // pointer return math.Sqrt(v.X*v.X + v.Y*v.Y) } v.Abs() // どちらも同じように呼べる func Abs(v Vertex) float64 { return math.Sqrt(v.X*v.X + v.Y*v.Y) } Abs(v) func Abs(v *Vertex) float64 { //TODO if v == nil { ... } return math.Sqrt(v.X*v.X + v.Y*v.Y) } Abs(&v) type MyFloat float64 func (f MyFloat) float64 Abs() float64 { if f < 0 { return float64(-f) } return float64(f) }
interface
type Abser interface { Abs() float64 } var a Abser f := MyFloat(-math.Sqrt2) v := Vertex{3, 4} a = f // a MyFloat implements Abser a = &v // a *Vertex implements Abser var abser Abser = &Vertex{} describe(abser) func describe(i I) { fmt.Printf("(%v, %T)\n", i, i) }
// type assertion var i interface{} = "hello" s := i.(string) fmt.Println(s) s, ok := i.(string) fmt.Println(s, ok) f, ok := i.(float64) fmt.Println(f, ok) f = i.(float64) // panic fmt.Println(f) // type switch 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 (t Type) String() string // を実装すれば Println() できる
error
error は基本的に使わない。 予想できるものは if で分岐する。 予想できないものだけ error にする。
type MyError struct { When time.Time What string } func (e *MyError) Error() string { return fmt.Sprintf("at %v, %s", e.When, e.What) } func run() error { return &MyError{ time.Now(), "it didn't work", } } func main() { if err := run(); err != nil { fmt.Println(err) } }
Reader
func main() { r := strings.NewReader("Hello, Reader!") b := make([]byte, 8) for { n, err := r.Read(b) // func (T) Read(b []byte) (n int, err error) fmt.Printf("n = %v err = %v b = %v\n", n, err, b) fmt.Printf("b[:n] = %q\n", b[:n]) if err == io.EOF { break } } }
Image
type Image interface { ColorModel() color.Model Bounds() Rectangle At(x, y int) color.Color }
concurrency
package main import ( "fmt" "sync" "time" ) func say1(ch chan string, s string) { for i := 0; i < 3; i++ { time.Sleep(100 * time.Millisecond) ch <- s } close(ch) } func concurrency1() { ch := make(chan string) go say1(ch, "hello world") for s := range ch { fmt.Println(s) } fmt.Println("end") } func say3(ch chan string, s string) { for i := 0; i < 3; i++ { time.Sleep(100 * time.Millisecond) ch <- s } } func concurrency3() { ch1 := make(chan string) ch2 := make(chan string) go say3(ch1, "hello") go say3(ch2, "world") for i := 0; i < 20; i++ { select { case s := <-ch1: fmt.Println(s) case s := <-ch2: fmt.Println(s) default: fmt.Println("...") time.Sleep(100 * time.Millisecond) } } } type SafeCounter struct { value int mux sync.Mutex } func (c *SafeCounter) add(wg *sync.WaitGroup) { defer wg.Done() c.mux.Lock() defer c.mux.Unlock() c.value++ } func lock() { c := SafeCounter{} var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go c.add(&wg) } wg.Wait() fmt.Println(c.value) } func main() { concurrency1() concurrency3() lock() }
other
golang は並列処理用。
_ust は高速処理用(c, c++ 後継) Rust は Go より圧倒的に速い。しかし,self キーワードが必要。