header image
header image

Go言語の文法を勉強して印象にのこったところまとめ。その3。

Go言語の文法を勉強して印象にのこったところまとめ。その3。

前回、前々回とgoの文法をまとめています。今回はその3です。

今回は

  • 配列
  • エラーハンドリング

です。

勉強に使用した本

参考にした本は例によってこちらの本です。感想などは以前の記事に書いたので割愛します。

改訂2版 基礎からわかる Go言語

早速文法のまとめを見ていきましょう。

文法のまとめ

配列、スライス、マップ

配列

配列は他の言語の配列とあまり変わらずGo言語の配列は動的ではなく、初期化時に配列の長さが決まるようで、動的配列として使いたい場合はスライスを使うのでGO言語で配列を使う機会は少ないようです。

とはいえ文法は知っておいたほうがよいので 下記に初期化の方法などは載せておきます。

// 配列型の宣言
var array [1] byte
var array2 [5]*int
var array3 [8][3]int64
var array4 [2]struct{ x, y int ]
// 配列の初期化

array1 := [5]float32{} // 長さ5の配列。各要素はゼロ値で初期化される。

array2 := [6]int{1, 2, 3, 4} // 長さ6の配列。要素の不足分はゼロ値で初期化される。

array3 := [...]string{"One", "Two", "Three"} // ...を記述すると要素数が長さとしてしようされる。

スライス

スライスは動的配列として使われるので、rubyやjavascriptの配列をイメージしている人は配列ではなくスライスを使うと覚えておくとよいみたいです。 とはいえスライスは参照型と呼ばれ実体は配列を参照しているようです。配列そのままを関数にわたしたりすると配列の値すべてが複製されてしまい 効率が悪いですが、スライスのような参照型を受け渡しすると参照情報のみがコピーされるのでデータが少なくすむという利点があります。

スライス式

配列からスライスを作成する、もしくはスライスから新たにスライスを作成するには「スライス式」を使用します。 スライス式は「[]」内に作成するスライスに含める要素の範囲を「:」で区切って記述します。

作成元の配列orスライス[下減値:上限値]
作成元の配列orスライス[下減値:上限値:キャパシティ]

キャパシティとはスライスから新たにスライスを作る場合に指定できる上限値の最大値で、スライスからスライスを作成する時は、 スライスの長さを超え、キャパシティの値までスライスできます。

また、文字列をスライスすることも可能で文字列をスライスすることで文字列を切り出すことができます。

var x sring = "abcde"[1:4]
// => "bcd"という文字列がxに格納される

スライスの初期化

配列をそのまま使うよりもスライスを使った方がスライスが可変長な分扱いやすいのですが、わざわざスライスとして使用するために 配列を作るのは手間なのでGo言語ではmake組み込み関数が用意されています。

make(スライス型, 長さ, キャパシティ)
make(スライス型, 長さ)
// 長さ10, キャパシティ20のスライスを作成
s1 := make([]int, 10, 20)

次にスライスの作成と初期化を同時に行う場合は、スライスリテラルを利用します。

s := []int{1, 2, 3, 4}

マップ

マップは他の言語でもあるようにキーと値の集合です。「辞書」や「連想配列」とも言われます。 マップ型はスライスと同じく参照型の一種で参照型の値を作成する場合はmake組み込み関数を使用します。

make(map[キーの型] 要素型, キャパシティの初期値)
make(map[キーの型] 要素型)

キャパシティはマップに格納可能な要素数ですがここで指定する値はあくまでも初期値でキャパシティは 必要に応じて自動で拡張されます。キャパシティの初期値は省略可能です。

マップの参照は配列と同様に添字を渡して参照するのですが

capitals := make(map[string] string)
capitals["日本"] = "東京"
capitals["アメリカ"] = "ワシントンDC"
capitals["中国"] = "北京"

また、マップは二つ目の戻り値でキーが存在するかを確認することができます。

capital, ok := capitals["イギリス"]
if ok {
  fmt.Println("登録済み", capital)
} else {
  fmt.Println("未登録", capital)
}

マップのキーとして使用できる値

マップのキーとして使用できる型は「関数型」「マップ型」「スライス型」以外で、比較演算子「==」「!=」が 実装されている必要があります。

マップの初期化

マップを作成と同時に初期化する場合は、マップリテラルを使用します。

capitals := map[string] string{
  "日本": "東京",
  "アメリカ": "ワシントンD.C",
  "中国": "北京"
}

エラーハンドリング

戻り値によるエラーハンドリング

GOでは戻り値に複数の値を返すことができますが、これをエラーハンドリングにも利用することができます。

Go言語の標準関すは処理結果とともに「errorインターフェース型」の値をエラー情報として返します。errorインターフェース は特定のパッケージ内で宣言されているものではなく、Go言語に組み込まれている型で、Errorメソッドを呼び出すことでエラーの詳細情報を 取得することができます。

file, err := os.Open("text.txt")
if err != nil {
  // エラーの詳細情報を出力
  fmt.Println(err.Error())
  os.Exit(1)
}

パニックとリカバリ

関数内でエラーが 発生し、その処理が致命的なエラーでただちに処理を中断させたい、もしくはリカバリが必要な時だけハンドリングしたいという場合には、 panic組み込み関数を呼び出して「パニック」という状態を発生させます。 ある関数内で「pnaic」を呼び出すと、その関数の実行は中断さ、順次呼び出し元をさかのぼり、最後にプログラム自体が終了します。 (この時defer文によって遅延していされた関数は実行されるそうです。)

さらに、recover組み込み関数を呼ぶとパニック状態を中断させることができるのですが、recoverは遅延実行された関数内でしか 使えないようです。

そのため、以下のようなコードでパニック状態を中断させることができます。

func f1(p bool) {
  defer func() {
    fmt.Println("defer start")
    err := recover() // リカバリ
    if err != nil {
      fmt.Println("catch panic:", err)
    }
    fmt.Println("defer end")
  }

  panic("panic!!!!!!!!!!")
}
// 実行結果
defer start
catch panic: panic!!!!!!!!!!
defer end

まとめ

ここまで配列・スライス・マップ、エラーハンドリングについてまとめてみました。 Goルーチンのまとめが残っているのですが、それなりのボリュームになりそうなので、記事を分けます。 このシリーズは次回で完結しそうです。では。