AtCoder初心者が迷って調べたGo文法

この記事は[Gopher道場アドベントカレンダー](https://qiita.com/advent-calendar/2018/gopherdojo)の14日目の記事です。

## はじめに
Gopher道場3期生の@kzkiq2ndです。

道場を卒業してしばらくして、文法練習のために競技プログラミングAtCoderにGoで入門しました。
これまで初心者向けのABC114,ABC115に参加しましたが全問正解はできていません。
次こそD問題を正解しようと練習中です。

本記事はAtCoder Beginner Contestの過去問を解いている中で、どう書けばよいか迷い調べた処理をまとめました。
これからAtCoderを始めるGo入門者の方に役立てるかもしれません。

※最新の初心者向けABC115の問題は[こんな感じ](https://abc115.contest.atcoder.jp/assignments)です。
※Gopher道場すごいおすすめです！
[メルペイがGopher道場をサポートする理由 #メルペイなう vol.16 #gopherdojo - mercan（メルカン）](https://mercan.mercari.com/entry/2018/06/14/113329)

### 文字列に関する処理
#### 文字列n番目の文字はインデックスで得られる

コードポイントがとれるので、文字にするならstring()関数を通す。

```go
	r := "Hello, playground"[1]
	fmt.Println(r) // => 101
	fmt.Println(string(r)) // => e
```

#### 文字列n番目の文字の比較はシングルクォート

比較はコードポイントのままで良い。

```go
	r := "Hello, playground"[1]
	if r == 'e' {
		fmt.Println(true) // => true
	}
	if r == "e" {} // => invalid operation: r == "e" (mismatched types byte and string)
```

文字コードポイント、runeに関しては以下の記事が参考になりました。
[Goのruneを理解するためのUnicode知識 - Qiita](https://qiita.com/seihmd/items/4a878e7fa340d7963fee)

#### 文字列の繰り返しはstrings.Repeat()
stringsパッケージの出番です。

```go
	fmt.Println(strings.Repeat("Hello", 3)) // => HelloHelloHello
```
https://play.golang.org/p/f3P0XnMefpZ

#### 文字列に含まれるかは strings.Contains（）
stringsパッケージ便利。

```go
	fmt.Println(strings.Contains("Hello, playground", "Hello")) // => true
```
https://play.golang.org/p/3HqByVrA2Ft

参考：[Go言語で文字列を処理する](https://blog.web-apps.tech/string-processing-in-go/)

### 数字に関する処理
#### 差の絶対値が欲しい math.Abs()
float64で扱うか、intで扱う作法が必要。

```go
	abs := int(math.Abs(float64(-100)))
	fmt.Println(abs) // => 100
```
https://play.golang.org/p/IIxMlHZQgVm

#### 2値の最小最大 math.Max, math.Min
float64で扱うか、intで扱う作法が必要。

```go
	var a, b float64
	a, b = 1, 10
	fmt.Println(math.Max(a, b)) // => 10
	fmt.Println(math.Min(a, b)) // => 1
```
https://play.golang.org/p/GFzpgbv2ebu

#### べき乗 math.Pow()

```go
	fmt.Println(math.Pow(2, 16)) // => 65536
	fmt.Println(math.Pow10(5))   // => 100000
```
https://play.golang.org/p/O0-8ONncp7g

#### intスライスの最小最大 sort.Ints()

```go
	s := []int{4980, 7980, 6980}
	sort.Ints(s)             // => [4980 6980 7980]
	fmt.Println(s[len(s)-1]) // => 7980 max
	fmt.Println(s[0])        // => 4980 min
```
https://play.golang.org/p/_5xTZuRnALh

#### 数字を文字列にする strconv.Itoa(int)

```go
	fmt.Println(strconv.Itoa(123)) // => "123"
```
https://play.golang.org/p/eUPMkhnwIQO

### その他
#### bool型のゼロ値はfalse
ゼロ値で初期化する習慣づくりに。

```go
	var b bool
	fmt.Println(b) // => false
```

参考：[ゼロ値を使おう #golang - Qiita](https://qiita.com/tenntenn/items/c55095585af64ca28ab5)

#### スライスの比較はreflect.DeepEqual
戻り値がスライスのテストを書くときに利用。

```go:ABC075Bのテストから抜粋
	input := []string{".....", ".#.#.", "....."}
	want := []string{"11211", "1#2#1", "11211"}
	if got := f(input); !reflect.DeepEqual(got, want) {
		t.Fatalf("want is %v, got is %v", want, got)
	}
```

#### 文字列スライスの全探索をrangeで書けるの忘れがち
ぐっとシンプルに書けます。

```go
	s := []string{"ABC", "DEF", "GHI"}
	for i := range s {
		for j := range s[i] {
			fmt.Print(string(s[i][j])) // => ABCDEFGHI
		}
	}
```
https://play.golang.org/p/R4zdpd1v47o

以上になります。
おすすめ文法や良い書き方、間違いの指摘があればお気軽に編集リクエストやメッセージ等お送りください。

## おまけA：次に見ると良い資料

### [Goで始めるAtCoderのススメ（初心者向け） - Qiita](https://qiita.com/syumai/items/d4d436eacc58ffbd8200)
「さぁ始めるぞ！」という方には@syumai さんの入門記事を参考にするのがおすすめです。まずは標準入力が扱えれば戦えます。

### [AtCoder に登録したら次にやること ～ これだけ解けば十分闘える！過去問精選 10 問 ～ - Qiita](https://qiita.com/drken/items/fd4e5e3630d0f5859067)
最初に解くのは、公式ページにも掲載されているAtCoder入門者チュートリアル10問がおすすめです。
記事中のサンプルコードはC++ですが、別の方がGoで解いた物もあります。

- [AtCoder に登録したら解くべき精選過去問 10 問を Go で解いてみた - Qiita](https://qiita.com/kakko_hatena/items/8969ddbf432bdd520fc4)

## おまけB：The Go Playground便利
コンテスト中でも簡単な文法確認をしたいときに[The Go Playground](https://play.golang.org/)で実行できるのが便利でした。
全体にいえる事ですが、AtCoderで使えるGo1.6とのバージョン差には注意です。

## おまけC：テストファーストで解くAtCoder
Goのテストパッケージを素早く扱う練習にと、問題を解く際に簡単なテストを書いています。

```go:ABC115A回答から抜粋
// 標準入力をパース
func main() {
	var d int
	fmt.Scan(&d)
	fmt.Println(eve(d))
}

// 問題の回答
func eve(d int) string {
	return "Christmas" + strings.Repeat(" Eve", 25-d)
}

// 回答関数のテスト
func TestEve(t *testing.T) {
	d := 22
	want := "Christmas Eve Eve Eve"
	if got := eve(d); got != want {
		t.Fatalf("want is %v, got is %v", want, got)
	}
}
```
https://play.golang.org/p/6_PcU4AHCCf

回答処理を関数とした簡単なテストですが、

1. 手元で回答検証が早く出来る
2. テーブルテストで複数パターン検証もできる
3. テストを書きながら回答を考える習慣がつく
4. 振り返りにテストがついている

こんな感じで、テストファーストを習慣づけるのに良いです。

ただしAtCoderはスピード競技でもあり、テスト書いてるだけ提出が遅くなりスコア伸びは悪そうです。
本番ではテストを使わず、過去問練習でテストを書くのはメリットが多いと思います。

※テストファーストで解いた問題をまとめました。
[AtCoder過去問精選10問をGo + テスト付きで解いてみた - Qiita](https://qiita.com/kzkiq2nd/items/4f390731da92894679e0)