ゼロから学ぶGo言語プログラミング(6) A Tour of Go 1~17まで

実践的な言語ガイドを見ながら制御構造の確認をしようと思っていましたが、ちょっと心変わりして、公式チュートリアルの「A Tour of Go」をひと通り進めることにしました。

A Tour of Go

f:id:belbo:20140616112930j:plain

これは、ブラウザで動作するインタラクティブなGoの簡易的な実行環境に、チュートリアルを添えたものです。 実行環境はGo Playgroundとほぼ同じですが、シンタックスハイライトが使えるなど、フロントエンドで少し違いもあります。

1.Hello, 世界

ツアーの先頭は、やはりHello Worldです。 これについては以前しっかり確認しているので、コードはスルーします。

チュートリアル本文には、このツアー環境の構成やショートカットなどの説明。 構成は"基本コンセプト、メソッドとインターフェース、並行性"となっていて、ショートカットは以下の2つが用意されています。

  • Shift + Enter : コードの実行
  • PageUp / PageDown : ページの切り替え

2.Go local

ツアーは多言語に対応していて、英語や日本語以外にも、スペイン語やフランス語、中国語や韓国語などでも進められます。 面白いのは、ヘブライ語カタルーニャ語ルーマニア語など、利用者のそう多くない言語がサポートされている点。 ロシア語などもっと話者の多いであろう言語がないので、有志が翻訳した言語から対応していっているのかも知れません。

3.The Go Playground

ツアーに使用するPlaygroundの説明。

  • ネットワークやファイルシステムへのアクセスができない
  • システム時刻は常に固定
  • シングルスレッドでしか動かない

4.Packages

パッケージのインポートについて、基本の説明。

気になったのはplayground環境ではmath/randがきちんと擬似乱数を返さず、結果は常に同じ値になる、という点。 乱数のシードを与えれば大丈夫、と書いてあるので、システム時刻が固定なのが理由でしょうか。

5.Imports

packageのimportは、複数まとめて書ける。 ということで、以下の3つは等価。

import "fmt"
import "math"
import (
    "fmt"
    "math"
)
import (
    "fmt"
)
import (
    "math"
)

importを書く場所は、先頭しかだめなんだろうか。

6.Exported names

Goのpackageは、大文字で指定した要素をエクスポート、という名前ベースの参照制御。

サンプルで配置されているコードは、math.piと小文字のpiを指定しているため、エラー。 この手のpackageに指定した要素がエクスポートされていない場合には、"cannot refer to unexported name ***"というエラーが検出されるようだ。

7.Functions

  • 関数宣言はfunc
  • 引数指定は、引数名の後ろに型を指定
  • 引数の括弧の後に戻り値の型を指定

なぜ型指定が後に来るのか、今は深追いせずにいよう。

8.Functions continued

型指定の省略記法。

func foo(a, b, c, d, e int, x, y, z string) int {
}

という風に、まとめて指定したければ、引数の順は型でまとまっている必要はある。

9.Multiple results

おお、ようやくお目にかかれた、複数の戻り値の返し方。

func foo(x, y int) (int, int) {
      return x+y, x*y
}

という風に、関数宣言の引数指定後に置く戻り値の型指定を、括弧に目的の個数の型を並べるようにし、returnで複数の値を渡す、ということだった。

もうひとつついでに気になったのは、

a, b := swap("hello", "world")

というコードの":="という記号。 代入のようだけど、多分この先出てくるだろう。

10.Named results

関数では戻り値に型だけではなく、予め名前を指定できるらしい。

そして名前を指定した戻り値が宣言されている場合、returnで返したい値をわざわざ指定しなくても済む。

しかし以下のように、戻り値名を指定しつつ、異なる値を返すこともできるようだ。

func split(sum int) (xx, y int) {
    xx = sum * 4 / 9
    y = sum - xx
    return sum, sum
}

これはちょっと混乱しそう。

11.Variables

やっと出てきた変数宣言。

JavaScriptなんかで見慣れた、var。 引数や戻り値の宣言と同じく、同一の型であれば、名前を複数ならべて、後ろに一括で型を書ける。

12.Variables with initializers

varによる変数の宣言時には、変数の初期化が出来る。 更にその初期化時には、型が自動判定される。

これ、浮動小点数の精度とか、リテラルで初期化しつつ、型も指定したい場合どうするんだろう。 変数側に型を付けるのかな。

13.Short variable declarations

関数内だけで使える、暗黙的型宣言を行う代入記法":="。 さっき出てきたのはこれでした。

この記法が関数内だけに限定される理由はなんだろう。 関数外ってことは、packageとしてエクスポートされ得る対象だとかいうことに関係があるんだろうか。

14.Basic types

やっと出会えた、標準の型一覧。

bool, string, intあたりはごく当たり前だけど、符号付きで整数を放り込むとoverflowだよと警告されるuintがある。 intとuintには、サイズなしのものと、8,16,32,64のサイズ付きがある。 サイズなしのものは、処理系で決まるのかな。 それとも、int32あたりの略記なのか。

floatは32か64か。 精度表記なしの"float"は無し。

byteがuint8のエイリアスとして定義されている。

見慣れないのは、runeとcomplex。

runeは、どうやらUnicodeの文字ひとつを表す型らしい。 chrとかruneと呼ぶのは、Go特有なんだろうか。 よくあるchrとかではUnicode文字という扱いが曖昧だから、新しい名前を付けたのか。

complexはなんなんだろう。 名前からして、複合的なデータを持つんだろうけど、謎。

そういえば、var宣言もimport同様、

var(
    foo int
    bar uint16
)

みたいにまとめ書きが出来たらしい。

そして、「初期化しつつ、型も自前で指定したい場合」は、やはり変数側に型を付けるで正解だった。

15.Constants

定数宣言はキーワードconstで。 これは関数内でも外でも同じ。

謎は、次の一文。

定数は、character、string、boolean、数値(numeric)のみで使えます。

character、string、boolean、数値(numeric)ってのは、組み込みの型のどれにどう対応しているのか、全然伝わってこない…。 そもそもconstには型が不要なのか??

16.Numeric Constants

さあ、これはよく理解できない。

数値定数は高精度な 値 ( values )です。型のない定数は、その状況によって必要な型を取ることになります。

constで宣言した定数は、それが数値であれば、「高精度な値」として扱われ、型は使用時に選択されるらしい。 定数は、ひとつの宣言を様々な状況で利用しうるから、変数での型とは異なる扱いなんだろうか。


取り敢えずここまで。