Go言語をとりあえず使ってみる

Go 1.9 で。使ってみると遊びなら C言語を使うくらいなら Go の方がいいという感じ。
Go 結構いいな。「見た目派」の自分としては、ソースの見た目がすっきりしているし。:= のおかげで型をあんまり明示的に書かなくても済むのが Rubyist にはいいっぽい。
それから $ go run がインタプリタみたいで超ラク。これはいい。

少しだけ触った感じでは、modify された C ? C言語はどうも面倒なのだけれど、これはちょっと使ってみたくなる。とにかくすっきりしている。

とりあえず FizzBuzz。switch 文の使い方がおもしろい。

package main
import "fmt"
import "strconv"

func get(i int) (st string) {
    switch 0 {
    case i % 15:
        st = "FizzBuzz"
    case i % 3:
        st = "Fizz"
    case i % 5:
        st = "Buzz"
    default:
        st = strconv.Itoa(i)
    }
    return
}

func main() {
    const num = 50
    ar := [num]string{}
    for i := 0; i < num; i++ {
        ar[i] = get(i + 1)
    }
    fmt.Println(ar)
}

結果。

[1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz
Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38
Fizz Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz]

 
フィボナッチ数列

package main
import "fmt"

func main() {
    a, b := 1, 0
    result := make([]int, 0, 50)
    for a < 1000 {
        a, b = a + b, a
        result = append(result, b)
    }
    fmt.Println(result)
}
//=>[1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987]

 
バブルソート。「メソッド」を使ってみました。Arr 型(ユーザー定義型)を使わずに直接的に配列で []int では、メソッドは呼べません。[]int は名前のない型なので。

package main
import "fmt"

type Arr []int

func (arr Arr) Bubble_sort() Arr {
    ar := append(Arr{}, arr...)    //=>スライスを複製(参照先を変える)  Arr{} は空スライス。
    ln := len(ar)
    for i := 0 ; i < ln - 1; i++ {
        for j := 1; j < ln - i; j++ {
            if ar[j - 1] > ar[j] {
               ar[j], ar[j - 1] = ar[j - 1], ar[j]
            }
        }
    }
    return ar
}

func (ar Arr) Sum() int {
    sum := 0
    for _, i := range ar {
        sum += i
    }
    return sum
}

func main() {
    given := Arr{5, 2, 1, 8, 6, 3}
    fmt.Println(reflect.ValueOf(given).Kind())    //given の型
    fmt.Println(given.Bubble_sort())
    fmt.Println(given)
    fmt.Println(given.Bubble_sort().Sum())
}

//slice
//=>[1 2 3 5 6 8]
//=>[5 2 1 8 6 3]    (破壊されていない)
//=>25
//[...]int{1, 2, 3, 4} は配列、[]int{1, 2, 3, 4] はスライス

given はスライスで、スライスは参照型なので、メソッド先で given が破壊されないよう append で複製しています。(←わかりにくかった!)
バブルソートして sum() でスライスの和を求めています。意味ないけれど(笑)。Rubyist としてはメソッドチェーンができるかやってみました。
sum() 内では ar の値を for 文で取り出すとき、インデックスの値を捨てなくてはいけないことに気づかなくてハマりました。
配列は長さが固定なのだけれど、スライスは配列の中で長さが可変の配列っぽい処理ができるわけだ。なるほど合理的。


エラトステネスの篩。

package main
import "fmt"
import "math"

const max = 100
var field [max + 1]int

func sieve() int {
    for i := 2; i <= int(math.Sqrt(float64(max))); i++ {
        if field[i] != 0 {continue}
        for j := 2; j <= max / i; j++ {
            field[i * j] = 1
        }
    }
    i := 0
    for j := 2; j <= max; j++ {
        if field[j] == 0 {
            field[i] = j
            i++
        } 
    }
    return i
}

func main() {
    fmt.Println(field[:sieve()])
}
//=>[2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97]

1000万までの篩を実行してみたところ(出力はなし)、0.331秒でした。ちなみに Swift で 0.234秒、Ruby で 3.01秒、Ruby FFI(本体部分は C)で 0.459秒というところです。C と同じくらいですか。
field[i++] = j みたいなインクリメント演算子の使い方はできないのですね。