何かを書き留める何か

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

『プログラミング言語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周りの話に興味があることが何となく見えてきた次第である。

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

去る2017年9月8日に早大理工にてPyCon JP 2017のカンファレンス1日目が行われた。 2014, 2015, 2016に続いて4回連続4回目の参加である。 今回は講演を聞くことよりもブースを聞いて回ることや話すことを中心においた。

Keynote Peter Wang

https://youtu.be/kIgGHTsig6gyoutu.be

Anacondaの設立者による基調講演。

Pythonとパッケージングと私 Atsushi Odagiri

youtu.be

今回はsetuptools周りのお話。 setup.pyは恥ずかしながら書いたことがなので、中々この知見を活かすことができずにいる。 pip install -U setuptoolsは忘れないようにしよう。

メディア会議

清水川さんのブログエントリに記録が残っている。

www.freia.jp

もっと裏話っぽい話が聞けると思っていたがそうでもなかった。 著者の皆様が執筆を行った経緯が持ち込みではなく依頼なので、いつでも引き受けることができるように素振りが必要だなと感じた。 その後行われていたMeet upは真剣に話す人たちが多くて近づけなかった。近づく勇気がなかったと言うべきか。

Djangoフレームワークのユーザーモデルと認証 Shinya Okano

www.youtube.com

ちょうど最近Djangoに触れているので、アプリケーションの肝となる認証を知りたくて参加した。 ビューがクラスビューになったりと進化を続けているので、使うのであればきちんとキャッチアップしていきたい。

Lightning Talks

www.youtube.com

  • 1組目はPyLadies Tokyoによる「ギャル語ほんやく」。ギャル語に詳しい人がいないという悩みに笑ってしまった。時間とともに変化する文脈依存言語となるのでコーパスが構築しにくそうである。

  • 2人目は@ymyzk によるWSGIのラインプロファイラ。

  • 4人目は@catcat_festivalによる暗号通貨取引を行うbotの話。バブリーな暗号通貨をbotに託す勇気が欲しい。

  • 5人目は@tn961irによるOSS Fridayの話。紹介と共に今後こうしたいという決意表明でもあったと思う。

  • 6人目は@nasa9084によるDockerの話。Python成分は何処へ。

  • 7人目は@yotchang4sによるJavaPythonインタプリタの話。これに憧れてオライリーの『言語実装パターン』を買ったほどである。

  • 8人目は@renyuanlyuによるカラオケの話。相変わらずすごい技術であり、最後まで聞けずに残念であった。

3人目、そう3人目ですね…。*1

Respect the Built-in Names

speakerdeck.com

前日までは全く別のテーマを考えていたが、 2017年9月6日に行われたReject Conでの反応や自分でスライドを作ったことによる考えの変化から、 あまり明文化されていないと思われる作法「組み込み函数を不用意に上書きしない」にフォーカスして発表してみることにした。 実際、listlistオブジェクトが代入されるケースやsum函数に0が代入するケースは多い。

スライドにある「悪い文明」の元ネタ(と私が認識している)は『もっとマンガで分かる!Fate/Grand Order』の第23話である。 www.fate-go.jp

「親御さんが泣くぞ」という話は昔からあるが、当初使おうとしたのは1936年の二・二六事件『兵に告ぐ』のビラであった。 刺激的すぎるので不採用としたが、心残りであったので口頭で出てきたと思われる。

idにだって人権がある」は事前に考えた内容ではなく、当日その場で口から出てきた言葉である。

感想ツイート

togetter.com

このようなうれしい感想をもらうことができてとてもうれしい。 題材が何だかんだみな遭遇してきたことなので共感がしやすく、自分でいうのもアレであるが笑いは取れていたと思う*2

また、何故組み込み函数や組み込みクラスが上書き可能であるのか、という話を懇親会でスタッフの方とした。 何故だろうか。TrueFalseのように新たな値を代入不可能にすることもできはするはずである。

*1:サムネイルの時点でネタバレしている。

*2:しかし、自分の発表を見ても面白いとは思えず、恥ずかしくなるのである。