APG4g（Go言語入門 APG4b）【1.00 ~ 1.02】

# 本記事について

競技プログラミングサイトの1つである[AtCoder](https://atcoder.jp/home)では、プログラミング学習教材の[APG4b(AtCoder Programming Guide for beginners)](https://atcoder.jp/contests/APG4b)が公開されています。使用言語はC++です。

また、sabaさんによって、[Python版APG4b](https://qiita.com/saba/items/b9418d7b54cce4b106e4)も書かれています。さらに、その他多くのプログラミング言語を使ったAPG4bの記事が公開されています。

本記事では以上のコンテンツに則り、Go言語版APG4bを書いてみたいと思います。

今回扱う内容は以下の通りです。

- [1.00. はじめに](#100-はじめに)
- [1.01. 出力とコメント](#101-出力とコメント)
- [1.02. プログラムの書き方とエラー](#102-プログラムの書き方とエラー)

本記事での目標は、以下の3点です。

1. AtCoderに解答コードを提出し、AC（正解）する
2. Go言語のプログラムについて、基本形を書けるようになる
3. Go言語のプログラムで会うエラーへの対処が出来るようになる

では、始めていきましょう！

## [1.00. はじめに](https://atcoder.jp/contests/apg4b/tasks/APG4b_a)

はじめに、AtCoderにコードを提出してみます。

### 手順

1. AtCoderに会員登録をする
1. [A - 1.00.はじめに](https://atcoder.jp/contests/apg4b/tasks/APG4b_a)のページを開く
1. 最下部の「言語」欄を「Go(1.14.1)」にする（バージョンは変わっているかもしれません）
1. 以下のコードを「ソースコード」欄にコピペし、提出（Submit）ボタンを押す
1. 「AC」となることを確認する

```golang: a_1.00.go
package main

import "fmt"

func main() {
    fmt.Println("Hello, world!")
}
```

AC（Accepted）と表示されれば、問題に対して正しく答えることが出来たことになります。おめでとうございます。

WA（Wrong Answer）やRE（Runtime Error）、CE（Compile Error）の時は、

- 表示する文字列の```Hello, world!```が間違ってないか（大文字/小文字/空白など）
- 括弧が正しく閉じているか
- 言語設定が誤っていないか（PythonやC++を選択していないか）

などを確認してください。

AtCoderには提出前に、書いたコードがAtCoder上で動くかどうか確認することができる[コードテスト](https://atcoder.jp/contests/apg4b/custom_test)ページがあります。提出する前にコードテストで動かしてみることも検討してみてください。

## [1.01. 出力とコメント](https://atcoder.jp/contests/apg4b/tasks/APG4b_b)

### キーポイント

- `package main`と`import "fmt"`は毎回最初に書く
- Go言語のプログラムは**main関数**から始まる
- `fmt.Println("文字列")`で文字列を出力できる
- `//`や`/* */`でコメントを書ける

| 書き方  | コメントになる場所             |
| ------- | ------------------------------ |
| `//`    | 同じ行の`//`と書いた場所の後ろ |
| `/* */` | `/*`と`*/`の間全て             |

Go言語のプログラムの基本形は次のプログラムになります。
`go run b_1.01.go`とコマンドを実行しても、このプログラムは何もしません。

```golang: b_1.01a.go
package main

func main() {
    // この部分が実行される
}
```

### main関数

Go言語のプログラムは`main関数`から始まります。上の`b_1.01.go`では以下の部分がmain関数です。

```golang: main関数
func main() {
    // この部分が実行される
}
```

Go言語のプログラムを起動すると、main関数の`{}`の中にある処理が動きます。

最初のプログラムを見てみましょう。
このプログラムは、`Hello, world!`という文字列を出力するプログラムです。

```golang: a_1.00.go
package main

import "fmt"

func main() {
    fmt.Println("Hello, world!")
}
```

```text: 実行結果
Hello, world!
```

main関数の中にある次の一行が、画面に文字列を表示させる（出力する）プログラムです。

```golang: 出力を行う部分
fmt.Println("Hello, world!")
```

Go言語では、画面に文字列などを出力する時に```fmt.Println()```を使います。`()`の中に出力させたいものを入れることで、文字列や数値などを出力させることが出来ます。

Go言語で文字列を扱う場合、`"`（ダブルクオーテーション）で囲む必要があります。
```fmt.Println()```は自動で文末で改行してくれます。

### 行の終わり

C++では行末に`;`が必要ですが、Go言語では必要ありません。Pythonと同様です。

※ 書いても問題なく動きますが、VS CodeなどでGo言語拡張機能を導入している場合やgofmtなどのコード整形ツールを使っている場合は改行に置き換えられます。

### 複数の出力

[a_1.00.go](#手順)のプログラムを使って、別の文字列を出力したい場合は`" "`の中身を変えれば良いです。

```golang: b_1.01b.go
package main

import "fmt"

func main() {
    fmt.Println("こんにちは世界")
}
```

```text: 実行結果
こんにちは世界
```

### 複数の出力

出力を複数回行うことも出来ます。
また、`()`内に`,`区切りで複数の文字列を書くことで、`c d`のように空白区切りで出力させることが出来ます。

```go: b_1.01c.go
package main

import "fmt"

func main() {
    fmt.Println("a")
    fmt.Println("b")
    fmt.Println("c", "d")
}
```

```text: 実行結果
a
b
c d
```

また、改行が必要無い場合は以下のように書くことも出来ます。

```go: b_1.01d.go
package main

import "fmt"

func main() {
    fmt.Print("a")
    fmt.Print("b")
    fmt.Print("c", "d")
}
```

`fmt.Print()`とすることで、改行せずに文字列を出力させることが出来ます。

```text: 実行結果
abcd
```

### 数値の出力

数値を出力する時は、`" "`を使わずに、直接書くことでも出力できます。

```go: b_1.01e.go
package main

import "fmt"

func main() {
    fmt.Println(2525)
}
```

```text: 実行結果
2525
```

### 全角文字

Go言語はUTF-8という文字コードを使ってプログラムが書かれることを前提としています。
UTF-8は日本語等の全角文字をサポートしているため、全角文字であってもそのまま使うことが出来ます。

しかし、多くのプログラムは半角英数字と記号で書かれており、全角文字で書くことはスタンダードではないため、半角文字で書くべきだと思います。

```go: b_1.01f.go
package main

import "fmt"

func main() {
    こんにちは世界 := "Hello, world."
    fmt.Println(こんにちは世界)
}
```

```text: 実行結果
Hello, world.
```

### コメント

コメントは人間がプログラムの動作を説明するためのメモ書きを残すための機能です。
プログラムとしての機能はありません。

Go言語でのコメントの例は以下のようになります。

```go: b_1.01g.go
package main

import "fmt"

func main() {
    fmt.Println("Hello")
    // fmt.Println("World")

    /*
    ここも
    全部
    コメントになります！

    空白行があっても大丈夫！
    */
}
```

```text: 実行結果
Hello
```

コメントには2種類の書き方があります。

| 書き方  | コメントになる場所             |
| ------- | ------------------------------ |
| `//`    | 同じ行の`//`と書いた場所の後ろ |
| `/* */` | `/*`と`*/`の間全て             |

### 練習問題

[EX1 - コードテストと出力の練習](https://atcoder.jp/contests/apg4b/tasks/APG4b_cv)を解いてみましょう。

<details><summary>解答（解けなかったら開いてください）</summary>

```go: 解答
package main

import "fmt"

func main() {
    fmt.Println("こんにちは")
    fmt.Println("AtCoder")
}
```

</details>

## [1.02. プログラムの書き方とエラー](https://atcoder.jp/contests/apg4b/tasks/APG4b_c)

### キーポイント

- スペース、改行、インデントを使ってプログラムを見やすくする
- Goは公式からプログラムの体裁を整えるツール（`gopls`や`gofumpt`が提供されている
- コンパイルエラーは文法のエラーで、プログラムは実行されない
- 実行時エラーは内容のエラーで、プログラムは強制終了される
- 論理エラーは内容のエラーで、プログラムは正しく動いているように見えてしまう

### スペースと改行

Go言語では、スペースと改行は同じ意味になります。

また、C++と同様に、Go言語はセミコロンで行末であることを明示することができ、
1つの行に1つの処理しか書かれていない場合、セミコロンを省略することが出来ます。

以下の2つのコードは同じ動きになります。

```go: c_1.02a.go
package main

import "fmt"

func main() {
    fmt.Println("a")
    fmt.Println("b")
    fmt.Println("c")
    fmt.Println("d")
}
```

```go : コード整形をしない例
package main; import "fmt"; func main() { fmt.Println("a"); fmt.Println("b"); fmt.Println("c"); fmt.Println("d"); }
```

```text: 実行結果
a
b
c
d
```

### Go言語のコード整形ツール

Go言語は公式が提供する`gopls`と`gofumpt`の2つの書式でコードをフォーマットしてくれます。
字下げ（インデント）や括弧などの記号の空白調整を行ってくれますし、何より可読性が向上するため有効にしておいて損はありません。

VS Codeでは、Go言語の公式から配布されている拡張機能をインストールすることで、セーブ時にコードを整形してくれます。

参考資料

- <https://code.visualstudio.com/docs/languages/go#_formatting>
- <https://marketplace.visualstudio.com/items?itemName=golang.Go>

### プログラムのエラー

Go言語はC++と同じコンパイル言語です。
そのため、予めプログラムを機械語に翻訳し、実行ファイルを作るコンパイル処理が必要です。

コンパイラがコードを読み解けなかった場合、コンパイルエラー（文法エラー）を起こします。

その他エラーもありますが、大まかな理解は以下の通りです。

- コンパイルエラー
    - 書いたプログラムの文法が間違えている
- 実行時エラー
    - 文法は間違えていなかったが、動かしてみたら致命的な間違いがあった
- 論理エラー
    - 文法も処理も間違えていないが、書いた人間が勘違いかタイプミスをしている

焦らずゆっくり直しましょう。

### コンパイルエラーの例

全角スペースをコード上に紛れ込ませるとこのようなエラーが出ます。

```go: 全角スペースが紛れ込んだ例
package main

import "fmt"

func main() {　// ← "{" の次に全角スペースが入っている
    fmt.Println("Hello, world!")
}

```

エラーログはこのようになります。
「`c_1.02b.go`の5行目14文字目が`\U+3000（全角スペース）`でGoでは読めない文字ですよ。」と言っています。消去すれば問題なく動きます。

※2行目はUndefined（定義されていない）と書かれているため、変数として認識されているのだと思います。

```shell: エラーログ
# command-line-arguments
./c_1.02b.go:5:14: invalid character U+3000 in identifier
./c_1.02b.go:5:14: undefined: 　
```

Go言語は使わないデータに対して敏感なので、使用しない変数が存在した場合、コンパイルエラーを起こします。

```go: 使用しない変数を入れている場合
package main

import "fmt"

func main() {
    hello := "Hello"
    world := "World"
    // fmt.Println(hello, world) // こっちは動く
    fmt.Println(hello) // Worldが使われないためコンパイルエラー
}
```

```text: エラーログ
./c_1.02c.go:7:2: world declared and not used
```

### 練習問題

 [EX2 - エラーの修正](https://atcoder.jp/contests/apg4b/tasks/APG4b_cu)を解いてみましょう。

```go: A君が書いたプログラム(ex2_error.go)
package main

import "fmt"

func main() {
    // \nは改行するための文字（エスケープシーケンス）です。
    fmt.Print("いつも, 2525 "\n") 
    fmt.Println("AtCoderくん"
}
```

```text: 標準エラー出力
./ex2_error.go:7:30: invalid character U+005C '\'
./ex2_error.go:7:31: syntax error: unexpected n in argument list; possibly missing comma or )
./ex2_error.go:7:35: newline in string
```

<details><summary>解答（解けなかったら開いてください）</summary>

```go: 修正したコード
package main

import "fmt"

func main() {
    // \nは改行するための文字（エスケープシーケンス）です。
    fmt.Print("いつも", 2525, "\n")
    fmt.Println("AtCoderくん")
}
```

</details>

## 第一章 （1.00 - 1.02）　おわりに

APG4gの1.00 - 1.02までの内容は以上です。お疲れさまでした。

以降の内容は別途投稿する予定です。

Pythonを普段書いている身で、Goを少し勉強してこの記事を書いてみました。
より良い書き方がありましたら適宜ご指摘お願いします。

蛇足 : APG4gはAtCoder Programming Guide for Gopherの略です。bを180°回転させたらgに見えませんか？

## 次に進むならこちら

[APG4g（Go言語入門 APG4b）【1.03 ~ 1.04】]()に進む

## 参考資料

- AtCoder / APG4b系
    - [APG4b](https://atcoder.jp/contests/APG4b)
    - [Python版 APG4b](https://qiita.com/saba/items/b9418d7b54cce4b106e4)
    - [AtCoder コードテスト](https://atcoder.jp/contests/apg4b/custom_test)
- Go言語ツール系
    - [Go for Visual Studio Code - VS Code Go言語拡張機能リンク](https://marketplace.visualstudio.com/items?itemName=golang.Go)
    - [Go in Visual Studio Code - VS Code Go言語拡張機能 ドキュメント](https://code.visualstudio.com/docs/languages/go#_formatting)