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 の別名

  • rune // int32 の別名
    // 文字そのものを表す
    // Unicode のコードポイントを表す

  • 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 キーワードが必要。