プログラミング歴半年のRubyistがGoを学び始めて戸惑った点

## はじめに
プログラミングの実務経験半年ほどのRubyistが、Goを学び始めて戸惑った点をまとめてみました。

## 戸惑った点その１　例外機構がない
Goには例外機構がありません。Rubyで言うところの `begin ~ rescue ~ end` みたいな例外処理構文がありません。
例えば何らかの関数を呼び出した際に処理が成功したかどうかを確認するには、戻り値から判断します。

```go
result, err := doSomething()
if (err != nil) {
    // エラー処理
}
```

`err` は[error型のインタフェース](https://golang.org/ref/spec#Errors)です。Goではこの `err` を処理することでエラーハンドリングを行います。
（合わせて学ぼう [defer, panic and recover](https://blog.golang.org/defer-panic-and-recover)）

## 戸惑った点その2　公開範囲は識別子の命名規則による
定数や関数などの公開範囲は、識別子（定数名や関数名）の**1文字目が大文字か小文字か**によって決まります。**1文字目が大文字の場合は他のパッケージから参照可**、**小文字の場合は他のパッケージからは参照不可**となります。Rubyで言う`private`みたいな仕組みは、Goでは識別子の命名規則によって実現しています。
例えば以下のようなhogeパッケージの場合、

```hoge.go
package hoge

const (
    MAX = 100
    min = 1
)

func DoFoo(n int) int {
    // 何らかの処理
}

func doBar(n int) int {
    // 何らかの処理
}
```

mainパッケージからの可視範囲は以下のようになります。

```main.go
package main

import "hoge"

hoge.MAX    // OK! -> hogeパッケージの定数MAXを参照できる
hoge.min    // NG! -> コンパイルエラー（mainパッケージからhogeパッケージの定数minは参照できない）

hoge.DoFoo(1)    // OK! -> hogeパッケージの関数DoFooを参照できる
hoge.doBar(1)    // NG! -> コンパイルエラー（mainパッケージからhogeパッケージの関数doBarは参照できない）
```

## 戸惑った点その3　オブジェクト指向で言うところのコンストラクタがない
Rubyで言うところの`initialize`は用意されていません。Goでは**型のコンストラクタ**というパターンを利用します。
型のコンストラクタを表す関数は`New[型名]`のように命名し（他のパッケージに公開しないのであれば `new[型名]`）、また、**対象の型のポインタ型を返す**ように定義するのが一般的です。
下記は構造体`User`型とその初期化のための関数`NewUser`の例です。

```main.go
package main

import "fmt"

type User struct {
    Id   int
    Name string
}

func NewUser(id int, name string) *User {
    u := new(User)
    u.Id = id
    u.Name = name
    return u
}

func main() {
    user := NewUser(1, "Bob")
    fmt.Println(user)  // => &{1, Bob}
}
```

初期化するという意味で似たニュアンスを持つ`init関数`がありますが、こちらは**パッケージの初期化**に使います。
（合わせて学ぼう [Package initialization](https://golang.org/ref/spec#Package_initialization)）

## 戸惑った点その4　配列とスライスの定義
Goにおいて「配列」は、拡張や縮小はできずサイズは常に固定です。「スライス」がいわゆる可変長配列にあたります。
これらの型の表現が似ていて少し戸惑いました。

```go
/* 配列を定義 */
// 要素数が3のint型の配列
var a0 [3]int
a1 := [3]int{}
// 要素数は省略可。省略した場合は初期値の数が要素数となる。
a2 := [...]int{1, 2, 3}

/* スライスを定義 */
// int型のスライス
var s0 []int
// 要素数と容量が5であるint型のスライス
s1 := make([]int, 5)  // 初期値指定なし
s2 := []int{1, 2, 3, 4, 5}  // 初期値指定あり
```

配列は要素数を含めて1つの型なので、型の定義に必ず要素数が必要になります。見た目に関していえば、最初の`[]`に要素数もしくは`...`が入ります。
スライスは可変長配列を表現するので、要素数に制限はありません。最初の`[]`には何も入りません。

## 戸惑った点その5　ポインタ型の定義
今までポインタを意識する言語はほぼやってこなかったので、ポインタ周りの文法に少し戸惑いました。

ポインタ型は対象の型の前に`*`をつけることで定義できます。

```go
// int型のポインタ
var p1 *int
// [3]string型のポインタ
var p2 *[3]string
```

演算子`&`を使って、任意の型からそのポインタ型を生成することができます。

```go
var i int
p := &i  // pはint型のポインタ
```

**ポインタ型の変数の前**に`*`をつけることで、そのポインタ型が指すデータのデリファレンスができます。

```go
var name string
p := &name
name = "Tom"
fmt.Println(*p)  // => "Tom"
*p = "Jerry"
fmt.Println(name)  // => "Jerry"
```

同じ`*`でも、**型の前についていればポインタ型の定義**、**ポインタ型の変数の前についていればデリファレンス**になります。

他に、指定した型のポインタを生成する組み込み関数`new`があります。`new`は主に構造体型のポインタ生成のために利用されるようです。

```go
type User struct {
    Id   int
    Name string
}

p := new(User)  // pは *User型
p.Id  // == 0
p.Name  // == ""
```

## 戸惑った点その6　メソッドの意味がオブジェクト指向で言うメソッドとは異なる
Goにおけるメソッドとは、**任意の型に特化した関数**です。
メソッドの定義は関数の定義と似ていますが、`func`とメソッド名の間に**レシーバの型とその変数名**を書きます。

```go
type Point struct{ X, Y int }

/* *Point型にRenderメソッドを定義 */
func (p *Point) Render() {  // レシーバは*Point型
    fmt.Printf("(%d, %d)\n", p.X, p.Y)
}
```

メソッドは`[レシーバ].[メソッド]`の形式で使います。上記のメソッドは以下のように使います。

```go
p := &Point{X:1, Y:2}  // pは *Point型
p.Render()  // => (1, 2)
```

また、`[レシーバの型].[メソッド]`でメソッドを関数型として参照することができます。

```go
f := (*Point).Render()
f(&Point{X:1, Y:2})  // => (1, 2)
```

## 戸惑った点その7　継承がない
Goはオブジェクト指向言語ではないので、オブジェクト指向で言う「継承」はありません。
Goでは型に柔軟性を持たせるための仕組みとして**インタフェース**が用意されています。
インタフェースは`interface{ メソッドのシグネチャの列挙 }`の形式で、**型が実装すべきメソッドが何か**を定義します。

例えばGoの組み込み型`error`型は以下のようにインタフェースとして定義されています。

```go
type error interface {
    Error() string
}
```

errorインタフェースを実装した型は以下のように定義します。

```go
type MyError struct {
    Message string
    ErrCode int
}

/* *MyError型にerrorインタフェースのメソッドを実装 */
func (e *MyError) Error() string {
    return e.Message
}
```

これにより、任意の関数で返すerror型の値としてMyError型を使うことができるようになります。

```go
func RaiseError() error {  // 戻り値の型はerror型
    return MyError{Message: "エラー発生", ErrCode: 1234}  // 戻り値にMyError型を使うことができる
```


インタフェースのポピュラーな使用方法は「異なる型に共通の性質を付与する」使い方です。
例えば、構造体のUser型とBook型それぞれのポインタ型にStringfyインタフェースを実装することで、それらをStringfy型のデータとしてまとめることができます。

```go
/* Stringfyインタフェースを定義 */
type Stringfy interface {
    ToString() string
}

/* 構造体型Userを定義 */
type User struct {
    Id   int
    Name string
}

/* *User型にToStringメソッドを定義（Stringfyインタフェースを実装） */
func (u *User) ToString() string {
    return fmt.Sprintf("ID: %d, Name: %s", u.Id, u.Name)
}

/* 構造体型Bookを定義 */
type Book struct {
    Id    int
    Title string
}

/* *Book型にToStringメソッドを定義（Stringfyインタフェースを実装） */
func (b *Book) ToString() string {
    return fmt.Sprintf("[ID]%d, [Title]%s", b.Id, b.Title)
}

/* *User型と*Book型をStringfy型のスライスにまとめる */
vs := []Stringfy{
    &User{Id: 1, Name: "Jack"},
    &Book{Id: 101, Title: "スターティングGo言語"},
}
```

また、インタフェースによって汎用性の高いメソッドを定義することができます。
以下の例では、Stringfyインタフェースを実装した型であれば、関数Printlnを呼び出すことができることを示しています。

```go
func Println(s Stringfy) {
    fmt.Println(s.ToString())
}

Println(&User{Id: 1, Name: "Jack"})  // => "ID: 1, Name: Jack"
Println(&Book{Id: 101, Title: "スターティングGo言語"})  // => "[ID]101, [Title]スターティングGo言語"
```

（合わせて学ぼう [Interface types](https://golang.org/ref/spec#Interface_types)）

## おわりに
以上、Goを学び始めて戸惑った点についてまとめてみました。いろいろ戸惑いはしましたが、Go言語、好きです。

## 参考文献
- [スターティングGo言語](https://www.amazon.co.jp/%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0Go%E8%A8%80%E8%AA%9E-CodeZine-BOOKS-%E6%9D%BE%E5%B0%BE-%E6%84%9B%E8%B3%80/dp/4798142417)
- [golang.org](https://golang.org/ref/spec)