APG4g（Go言語入門 APG4b）【1.05】

# 本記事について

本記事は、[APG4g（Go言語入門 APG4b）【1.03 ~ 1.04】](https://qiita.com/Nub/items/2b9756ef433348eceb94)の続きです。
もし、前の記事を読んでいない、もう一度見たい等ありましたら見ていただけると幸いです。

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

- [1.05. プログラムの実行順序と入力](#105-プログラムの実行順序と入力)

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

1. Go言語のプログラムが実行される流れを知る
2. Go言語が標準入力をどうやって受け取るかを知り、書けるようになる
3. Go言語を使って、文字列を整数などの色々なデータ型に変換できるようになる

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

## [1.05. プログラムの実行順序と入力](https://atcoder.jp/contests/apg4b/tasks/APG4b_f)

### キーポイント

- プログラムは上から下へ順番に実行される
- `bufio.Scanner`で入力を受け取ることが出来る

### プログラムの実行順序

基本的に、プログラムは上から順に実行されます。

```go: f_1.05a.go
package main

import "fmt"

func main() {
    var name int

    name = 10

    fmt.Println(name)

    name = 5

    fmt.Println(name)
}
```

```text: 実行結果
10
5
```

### 入力

プログラムの実行時にデータの入力を受け取る方法を見ていきましょう。
「入力機能」を使うことにより、プログラムを書き換えなくても様々な計算を行えるようになります。

入力を受け取るには、`bufio.Scanner`を使います。

次のプログラムは、入力として受け取った数値を10倍、20倍にして出力するプログラムです。

```go: f_1.05b.go
package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
)

func main() {
    // 標準入力から受け取るスキャナを作成
    input := bufio.NewScanner(os.Stdin)

    // 1行読み込む
    input.Scan()

    // aという変数に文字列を数値に変換した結果を保存（初期化）
    a, _ := strconv.Atoi(input.Text())
    fmt.Println(a * 10)

    // bという変数に文字列を数値に変換した結果を保存（初期化）
    b, _ := strconv.ParseInt(input.Text(), 0, 0)
    fmt.Println(b * 20)
}
```

`bufio.NewScanner(os.Stdin)`で、標準入力（`os.Stdin`）から入力を受け取るスキャナ（読み取り機）を作成します。

今回は`input`という変数にスキャナを初期化して代入しています。

`Scan()`は1行の入力を受け取ります。
さらに、`Text()`とすることで、受け取った入力を文字列として取得することができます。

int型として受け取るためには`strconv.Atoi()`、もしくは`strconv.ParseInt()`を使ってint型に変換してあげる必要があります。

`strconv.ParseInt()`を使う場合、`Text()`の後ろにカンマ区切りで`0`を2回入れることで`int`型で入力を受け取ることが出来ます。

```text:入力
5
```

```text:実行結果
50
100
```

#### 整数以外のデータの入力

整数以外のデータを受け取りたい時は、`strconv`を使って必要な方に変換する必要があります。

実数（浮動小数）を受け取る時は、`strconv.ParseFloat`を使う必要があります。`strconv.ParseInt`の時の様に、後ろにカンマ区切りで1回だけ`64`と書いてあげてください。

```go:f_1.05.go
package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
)

func main() {
    // 標準入力から受け取るスキャナを作成
    input := bufio.NewScanner(os.Stdin)

    // 1行読み込む
    input.Scan()

    // 文字列として受け取る
    text := input.Text()

    // 実数（小数付きの数値）として受け取る
    real, _ := strconv.ParseFloat(input.Text(), 64)

    fmt.Println(text, real*2)
}
```

```text :入力
3.14
```

```text :実行結果
3.14 6.28
```

#### 空白区切りの入力

`bufio.Scanner`の`Scan()`は1行の入力を受け取り、`Text()`で文字列を取得できます。

```go: f_1.05d.go
package main

import (
    "bufio"
    "fmt"
    "os"
    "reflect"
)

func main() {
    input := bufio.NewScanner(os.Stdin)
    input.Scan()

    a := input.Text()

    fmt.Println(a, reflect.TypeOf(a))
}
```

```text :入力
10 20 30
```

```text :実行結果
10 20 30 string
```

そのため、空白区切りの入力を受け取ると、上の実行結果のように、`"10 20 30"`という文字列として代入されてしまいます。

#### 文字列の分割

文字列を分解する場合、`strings.Split`を使って文字列を分解してあげる必要があります。

`strings.Split`を使う場合、`()`の中は`(分解される文字列, 区切り文字)`という順番で書いてください。

また、分解した結果（今回は`list`という変数）は`変数名[前から数えてn番目]`という形式で取得することが出来ます。

`前から数えてn番目`というのは`0`番目、`1`番目、...と0から始まる連続した整数です。※人間は1から数えがちですが、コンピュータでは0から数えることが一般的です。

```go: f_1.05e.go
package main

import (
    "bufio"
    "fmt"
    "os"
    "reflect"
    "strings"
)

func main() {
    input := bufio.NewScanner(os.Stdin)
    input.Scan()

    list := strings.Split(input.Text(), " ")
    a, b, c := list[0], list[1], list[2]

    fmt.Println(a, reflect.TypeOf(a))
    fmt.Println(b, reflect.TypeOf(b))
    fmt.Println(c, reflect.TypeOf(c))
}
```

```text :入力
10 20 30
```

```text :実行結果
10 string
20 string
30 string
```

こうすることで、`"10 20 30"`が空白区切りで分割されて、
`10`（空白区切りでの`0`番目）、
`20`（空白区切りでの`1`番目）、
`30`（空白区切りでの`2`番目）の3つにすることが出来ます。

#### 複数行の入力

`bufio.Scanner`の`Scan()`は1行の入力を受け取るものなので、
入力が複数行ある場合はその行数分書いてあげる必要があります。

```go: f_1.05g.go
package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    input := bufio.NewScanner(os.Stdin)

    input.Scan()
    s1 := input.Text()

    input.Scan()
    s2 := input.Text()

    fmt.Println(s1, s2)
}
```

```text:入力
Hello
10
```

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

### 細かい話

<details><summary>Goの標準入出力の細かい話です</summary>

`fmt.Scan()`でも入力を受け取ることが出来ますが、Goで競技プログラミングをする上で安易に使うとTLE（Time Limit Exceeded : 実行制限時間の超過）になります。

以下のプログラムは、[複数行の入力](#複数行の入力)のプログラムを`fmt.Scan()`を使って実装した例です。

```go:f_1.05_ex.go
package main

import (
 "fmt"
)

func main() {
 var (
  s1 string
  s2 string
 )

 fmt.Scan(&s1, &s2)
 fmt.Println(s1, s2)
}
```

実は、`fmt.Scan()`は簡潔に書くことができ便利な半面、競技プログラミングにおいて致命的になりうる**時間がかかるというデメリット**があります。そのため、文字列から色々変換しなくてはなりませんが、`bufio.Scanner`を使った方法だけを紹介しました。

自分の中では、`fmt.Scan()`は「入力が1行の時のみに使う」のが良いと考えており、**複数行の入力を受け取らなければならない場合、`bufio`を使って入力を受け取る**べきだと考えています。

詳細は、ren510rev(Ren Goto)さんの記事[【競プロ】ScanningでTLEが発生してコケる](https://qiita.com/ren510dev/items/38fe6d09831d08fde537)を御覧ください。
</details>

### 練習問題

[EX5 - A足すB問題](https://atcoder.jp/contests/apg4b/tasks/APG4b_cr)を解いてみましょう。

```go: コピーするプログラム
package main

func main() {
    // ここにプログラムを追記
}
```

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

```go: 解答
package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
    "strings"
)

func main() {
    input := bufio.NewScanner(os.Stdin)
    input.Scan()

    list := strings.Split(input.Text(), " ")
    a, _ := strconv.ParseInt(list[0], 0, 0)
    b, _ := strconv.ParseInt(list[1], 0, 0)

    fmt.Println(a + b)
}
```

</details>

## 第一章 （1.05）　おわりに

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

以降の内容は別途投稿する予定です。
より良い書き方がありましたら適宜ご指摘お願いします。

Goの標準入出力って中々疲れますね（Javaより少し面倒なレベル）

## 次に進むならこちら

工事中

## 参考資料

- 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)
- Go言語の機能系
    - [Keywords - The Go Programming Language Specification](https://go.dev/ref/spec#Keywords)
    - [Golangでの文字列・数値変換 - 小野マトペの納豆ペペロンチーノ日記](https://matope.hatenablog.com/entry/2014/04/22/101127)
    - [Integer literals - The Go Programming Language Specification](https://go.dev/ref/spec#Integer_literals)
    - [【競プロ】ScanningでTLEが発生してコケる](https://qiita.com/ren510dev/items/38fe6d09831d08fde537)
    - [Representability - The Go Programming Language Specification](https://go.dev/ref/spec#Representability)
- その他
    - [NaN - Wikipedia](https://ja.wikipedia.org/wiki/NaN)