8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

本記事について

本記事は、APG4g(Go言語入門 APG4b)【1.03 ~ 1.04】の続きです。
もし、前の記事を読んでいない、もう一度見たい等ありましたら見ていただけると幸いです。

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

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

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

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

1.05. プログラムの実行順序と入力

キーポイント

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

プログラムの実行順序

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

f_1.05a.go
package main

import "fmt"

func main() {
    var name int

    name = 10

    fmt.Println(name)

    name = 5

    fmt.Println(name)
}
実行結果
10
5

入力

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

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

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

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型で入力を受け取ることが出来ます。

入力
5
実行結果
50
100

整数以外のデータの入力

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

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

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)
}
入力
3.14
実行結果
3.14 6.28

空白区切りの入力

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

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))
}
入力
10 20 30
実行結果
10 20 30 string

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

文字列の分割

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

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

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

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

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))
}
入力
10 20 30
実行結果
10 string
20 string
30 string

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

複数行の入力

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

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)
}
入力
Hello
10
実行結果
Hello 10

細かい話

Goの標準入出力の細かい話です

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

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

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が発生してコケるを御覧ください。

練習問題

EX5 - A足すB問題を解いてみましょう。

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

func main() {
    // ここにプログラムを追記
}
解答(解けなかったら開いてください)
解答
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)
}

第一章 (1.05) おわりに

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

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

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

次に進むならこちら

工事中

参考資料

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?