Go言語イベントDevquizの過去問題集（Gopher入試シリーズ）

最近のGoのイベントでDevquiz枠を設けられるケースが出てきたけど、答え合わせが会場で行われたりするしまとまってるところがないので作った。（あと、間違えた人が気づかないんじゃないか説）

# 原則

- 現在募集中のイベントのDevquizの答えは公開しません。
  - コメントにも書かないでね
  - 問題は忘れそうなので、書いておくかも。
- イベントに参加した or 存在に気づいたら随時、更新する(予定!)。 
- この記事に書いた答えで、間違ってたら訂正は受け付けます。（別解Welcome!!）

# 過去問

## Go Conference 2018 Spring

### 問題

次のプログラムを実行しようとした場合に何がおきますか？

```go
package main

import (
    "fmt"
)

type Hoge struct{}

func (h *Hoge) M() {
    fmt.Println(h)
}

func main() {
    var h *Hoge
    h.M()
}
```

選択肢

```
1. コンパイルエラー
2. パニックが発生
3. <nil>と表示される
4. 何も表示されない
```

### 解答

`3. <nil>と表示される`
何も格納していないHogeをポインタにしているのでnilになります。
それを表示しているので`<nil>`が表示されます。

## golang.tokyo #14

### 問題

次の関数`f`を実行した場合に何がおきますか？

```go
func f() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println(r)
        }
    }()

    done := make(chan struct{})
    go func() {
        panic("hoge")
        close(done)
    }()
    <-done
    fmt.Println("fuga")
}
```

選択肢

```
1. コンパイルエラー
2. パニックが発生
3. <nil>と表示される
4. 何も表示されない
```

### 解答

`2. パニックが発生`
https://play.golang.org/p/bM84kHgqg2i

`f()`と別のgoroutineでPanicが起きているため、deferされたrecoverは実行されない

## golang.tokyo #15

### 問題

以下のテスト関数TestMyInt_Incが成功するように、Incメソッドを修正してください。 なお、Incメソッド以外は変更しないで~~す~~ください。

```go
package main

import "testing"

type MyInt int

// テストが通るように以下のメソッドを修正させてください
func (n MyInt) Inc() {
    n++
}

// テストは変更しないで下さい
func TestMyInt_Inc(t *testing.T) {
    var n MyInt
    n.Inc()
    if n != 1 {
        t.Errorf("want %d, got %d", 1, n)
    }
    n = 10
    n.Inc()
    if n != 11 {
        t.Errorf("want %d, got %d", 11, n)
    }
}
```

### 解答

修正箇所

```go
// テストが通るように以下のメソッドを修正させてください
func (n *MyInt) Inc() {
    *n++
}

```

- MyIntをポインタ渡しにするだけ
- `MyInt.Inc()`で結果を返すようにすると、カウントアップされた結果は返りますが、テストの修正が必要になるため、問題の条件を満たさないので、NG

## golang.tokyo #16

### 問題

以下のテスト関数Testが成功するように、Stringメソッドを修正してください。 なお、Stringメソッド以外は変更しないでください。

```go
package main

import (
    "fmt"
    "testing"
)

type Hex int

// テストが通るように以下のメソッドを修正させてください
func (h Hex) String() string {
    return fmt.Sprintf("%x", h)
}

// テストは変更しないでください
func Test(t *testing.T) {
    cases := map[string]struct {
        h Hex
        e string
    }{
        "100->64": {h: 100, e: "64"},
        "16->10":  {h: 16, e: "10"},
    }
    for n, tc := range cases {
        t.Run(n, func(t *testing.T) {
            if s := tc.h.String(); s != tc.e {
                t.Errorf("want %q, got %q", tc.e, s)
            }
        })
    }
}
```

### 解答

修正箇所

```go
// テストが通るように以下のメソッドを修正させてください
func (h Hex) String() string {
    return fmt.Sprintf("%x", int(h))
}
```

- `h`を`int`にキャストする

## golang.tokyo #17

### 問題

以下のテスト関数Testが成功するように、IsAllEven関数を修正してください。 なお、IsAllEven関数以外は変更しないでください
ヒント：[初級者向けGoの落とし穴と解説 / Traps and Explanations in Go](https://speakerdeck.com/budougumi0617/traps-and-explanations-in-go)

```go
package main

import (
    "fmt"
    "testing"
)

type ErrNotEven struct {
    N int
}

func (err *ErrNotEven) Error() string {
    return fmt.Sprintf("%d is not even", err.N)
}

// IsAllEvenだけを編集し、テストが通るようにしてください
func IsAllEven(ns ...int) error {
    var err *ErrNotEven
    for n := range ns {
        if n%2 != 0 {
            err = &ErrNotEven{N: n}
            break
        }
    }
    return err
}

func Test(t *testing.T) {
    cases := map[string]struct {
        ns       []int
        hasError bool
    }{
        "1,2,3": {ns: []int{0, 1, 2}, hasError: true},
        "1,3,5": {ns: []int{1, 3, 5}, hasError: true},
        "0,2,4": {ns: []int{2, 4, 6}, hasError: false},
    }

    for n, tc := range cases {
        tc := tc
        t.Run(n, func(t *testing.T) {
            err := IsAllEven(tc.ns...)
            switch {
            case err != nil && !tc.hasError:
                t.Error("unexpected error:", err)
            case err == nil && tc.hasError:
                t.Error("expected error has not occurred")
            }
        })
    }
}
```

### 解答

https://play.golang.org/p/kKM7ZOy-AzD

修正箇所

```go
// 修正前
var err *ErrNotEven

// 修正後
var err error
```

```go
// 修正前
for n := range ns {

// 修正後
for _, n := range ns {
```

## golang.tokyo #27

### 問題

以下のコードを実行すると何が出力されるか答えよ。

```go
package main

import "fmt"

func main() {
    switch ok := false; {
    case true:
        fmt.Println("true", ok)
    case false:
        fmt.Println("false", ok)
    default:
        fmt.Println("default")
    }
}
```

### 解答

https://play.golang.org/p/VdYupMMMQut

説明

内容としては、下記コードを実行したのと同じです。
okに代入しているだけで、switchの分岐条件には一切関与していません。
switchのデフォルトはtrueなので、 `case true` に該当します。

```go
package main

import "fmt"

func main() {
    ok := false
    switch {
    case true:
        fmt.Println("true", ok)
    case false:
        fmt.Println("false", ok)
    default:
        fmt.Println("default")
    }
}
```