何かを書き留める何か

数学や読んだ本について書く何かです。最近は社会人として生き残りの術を学ぶ日々です。

『プログラミング言語Go』読書記録 その2

電池入りの言語

プログラミング言語Go』、今回は1.4から1.8まで。

1.4 GIFアニメーション

リサージュ曲線を描く。リサージュといえば電通大の校章である。

校章・コミュニケーションマーク│電気通信大学

1.4はconst宣言、コンポジットリテラルインスタンス生成、浮動小数点の演算が主題であるが、詳細は後の章に書かれているので、ここでは単純にリサージュを楽しむことにする。 const宣言内部は=で揃えてある。これはgofmtが自動で行ってくれるのでプログラマは普通に入力すればよい。

package main

import (
    "image"
    "image/color"
    "image/gif"
    "io"
    "math"
    "math/rand"
    "os"
    "time"
)

var palette = []color.Color{color.Black, color.RGBA{0x00, 0xFF, 0x00, 0xff}}

const (
    whiteIndex = 0
    blackIndex = 1
)

func main() {
    rand.Seed(time.Now().UTC().UnixNano())
    lissajous(os.Stdout)
}

func lissajous(out io.Writer) {
    const (
        cycles  = 5
        res     = 0.001
        size    = 100
        nframes = 64
        delay   = 8
    )
    freq := rand.Float64() * 3.0
    anim := gif.GIF{LoopCount: nframes}
    phase := 0.0
    for i := 0; i < nframes; i++ {
        rect := image.Rect(0, 0, 2*size+1, 2*size+1)
        img := image.NewPaletted(rect, palette)
        for t := 0.0; t < cycles*2*math.Pi; t += res {
            x := math.Sin(t)
            y := math.Sin(t*freq + phase)
            img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5), blackIndex)
        }
        phase += 0.1
        anim.Delay = append(anim.Delay, delay)
        anim.Image = append(anim.Image, img)
    }
    gif.EncodeAll(out, &anim)
}

実行するには、以下のようにコマンドを実行する。 標準でGIFを扱えるのは中々すごい。

$ go build lissajous.go
$ lissajous.exe > out.gif

『プログラミング言語Go』読書記録 その1

第二言語を学ぶ時期が来た

以前、勉強のために『プログラミング言語Go』を購入した。

www.kinokuniya.co.jp

最近、とある野望を抱いて「Go言語で実装してみよう」と思い立ったが、さすがにGo言語を全く知らない状態で実装を進めても無理があることがすぐにわかった。 そのため、積読状態であった『プログラミング言語Go』を読むことにした。 ただ読んでも継続できないと思ったので、ここのブログにエントリを書きこ残すことにする。

今回は1.1から1.3まで。

1.1 ハロー、ワールド

伝統のHello, World。

// helloworld.go
package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello, 世界")
}
  • 実行するにはgo run helloworld.goを実行。ただし、今回はJetBrainsのGoglandを使っているのでCtrl+F10を押すか緑の矢印を押すだけ。
  • 各ソースファイルはpackage宣言から始まる。続いてインポートするパッケージを並べる。この順序は必ず守る必要がある。さもなければexpected 'package', found 'import'となる。
  • fmtはフォーマットされた入出力を扱う函数があるパッケージ。
  • mainパッケージは特別で、単独で実行可能なプログラムを定義する。
  • 函数宣言は予約語func、関数名、パラメータリスト(今回は空)、結果のリスト(今回は空)、本体からなる。
  • 同じ行2つ以上の文や宣言が現れない限り、文や宣言の最後にセミコロンを必要としない。「事実上、ある種のトークンの後の改行はセミコロンへ変換されます。」とある。
  • Goのコードを解析するためには改行する場所が問題となる。gofmtツールでコードを標準書式へ書き換える。

1.2 コマンドライン引数

// echo1.go
package main

import (
    "fmt"
    "os"
)

func main() {
    var s, sep string
    for i := 1; i < len(os.Args); i++ {
        s += sep + os.Args[i]
        sep = " "
    }
    fmt.Println(s)
}
  • osパッケージはプラットフォームとは独立した形式でOSを扱うためのパッケージ。Pythonosと目的は同じと思われる。
  • コマンドライン引数はos.Argsで扱う。os.Argsは文字列のスライスで動的に大きさが決まる配列要素のシーケンス。Pythonではsys.argsで配列であった。
  • os.Args[0]でコマンド自身の名前。os.Args[1:len(os.Args)]`が引数。インデックスの指定は半開。
  • Goglandのフォーマットと、gofmtは微妙に動作が異なる。Goglandの設定を変更すれば保存時にgofmtgoimportsが実行される。
  • varで変数宣言。変数が明示的に初期化されない場合は暗黙的に変数の型に対するゼロ値に初期化される。
  • forループはGoで唯一のループ文。C言語風の文、範囲を指定するものがある。
// echo2.go
package main

import (
    "fmt"
    "os"
)

func main() {
    s, sep := "", ""
    for _, arg := range os.Args[1:] {
        s += sep + arg
        sep = " "
    }
    fmt.Println(s)
}

効率の良い方法はstringsJoinを使うことである。

//echo3.go
package main

import (
    "fmt"
    "os"
    "strings"
)

func main() {
    fmt.Println(strings.Join(os.Args[1:], " "))
}

1.3 重複した行を見つける

// dup1.go
package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    counts := make(map[string]int)
    input := bufio.NewScanner(os.Stdin)
    for input.Scan() {
        counts[input.Text()]++
    }
    for line, n := range counts {
        if n > 1 {
            fmt.Printf("%d\t%s\n", n, line)
        }
    }

}
  • if の条件部分は丸括弧で囲まない。本体は波括弧で囲む。
  • make(map[string]int)で文字列がキーで整数値が値である空のマップを作成する。makeにはほかの用途もある(がまだ書かれていない)。
  • マップの繰り返しの順序は規定されていない。
  • input := bufio.NewScanner(os.Stdin)で標準入力から読み込むスキャナができる。input.Scan()を呼び出すごとに1行読み込み改行文字を取り除く。中身はinput.Text()で取り出す。
  • fmt.PrintfC言語みたいなフォーマットされた文字列を出力する。
// dup2.go
package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    counts := make(map[string]int)
    files := os.Args[1:]
    if len(files) == 0 {
        countLines(os.Stdin, counts)
    } else {
        for _, arg := range files {
            f, err := os.Open(arg)
            if err != nil {
                fmt.Fprintf(os.Stderr, "dup2: %v\n", err)
                continue
            }
            countLines(f, counts)
            f.Close()
        }
    }
    for line, n := range counts {
        if n > 1 {
            fmt.Printf("%d\t%s\n", n, line)
        }
    }
}

func countLines(f *os.File, counts map[string]int) {
    input := bufio.NewScanner(f)
    for input.Scan() {
        counts[input.Text()]++
    }
}
  • os.Openはファイル*os.Fileとエラーの結果を返す。nilと一致するかどうかで成功の可否を判定する。C言語っぽい。
  • このファイル処理はストリーム処理となる。
// dup3.go
package main

import (
    "fmt"
    "io/ioutil"
    "os"
    "strings"
)

func main() {
    counts := make(map[string]int)
    for _, filename := range os.Args[1:] {
        data, err := ioutil.ReadFile(filename)
        if err != nil {
            fmt.Fprint(os.Stderr, "dup3: %v\n", err)
            continue
        }
        for _, line := range strings.Split(string(data), "\n") {
            counts[line]++
        }
    }
    for line, n := range counts {
        if n > 1 {
            fmt.Printf("%d\t%s\n", n, line)
        }
    }
}
  • ioutil.ReadFileはファイル全体を一気にメモリへ読み込む函数。楽であるが、ファイルが大きいと辛そう。

感想

  • まだ最初の数ページしか読めていない段階であるが、標準ライブラリが充実したC言語という印象。当然この印象は今後覆されるはずである。
  • ファイルの読み書きがPythonと比べて面倒である。Javaでも面倒だなと思ったので、型を考慮したファイルの読み書きはどうしてもこうなってしまうのかもしれない。
  • PyCharmと比べてGoglandは完成度がそれほど、という印象。Early Access Programsに文句を言うほうがおかしいけど。

Pycon JP 2017 2日目に参加しました。

去る2017年9月9日に早大理工にてPyCon JP 2017のカンファレンス2日目が行われた。 2014, 2015, 2016に続いて4回連続4回目の参加である。 今日は自社のブースにて様子を見たり、知り合いの方と世間話をする日であった。

自社ブース

自社ブースではアンケートに答えていただいた方やノベルティグッズに書かれたクイズに回答して頂いた方にどら焼きを配布していた。 幾分初めてのブースであったので適切などら焼きの量を見積もることは難しかったであろう。

世間話

本当に世間話なので公開できるような話はないが、このように長く話す機会もあまりないのでとても楽しかった。

Pythonにおけるデバッグ手法 TakesxiSximada

www.youtube.com

デバッグのテクニックよりもツールに着目した講演。Python標準のデバッガはpdbであるが、IPythonを入れて拡張したものなどPyCharmのデバッガをメインに使っている自分からは新鮮に感じる発表であった。

python勝ち抜きバトル!! Motohiro Ueki

www.youtube.com

クイズの問題を何問か提供した。 その内の1つ、import antigravityを問うのを提供したが、ぱっと見の異様さが気に入っている。

LT

www.youtube.com

驚いたのは昨日の自分のLTに対するアンサーLTが存在したことである。

内容は尤もで、「組み込みの名前を上書きするなという主張はわかった、ではどうすればよいのか?」という現実的かつ確実な回答である。

最後に

過去3年間は一般参加者であり、講演を中心に聞いて回っていた。 今年は知り合いも増え、また自社のブースがあったので立ち回り方も変わった。 人と話すことを中心においたらほとんど講演を聞いていないことに気づいた。 講演は必要ならばYoutubeで確認できること、これだ!と思う講演があまりなかったことが要因である。 自分は言語のコア部分の話やWeb周りの話に興味があることが何となく見えてきた次第である。