[Golang] fmtパッケージを使った標準入出力

2021-09-29 hit count image

Golangで標準入出力に使えるfmtパッケージについて説明します。

概要

今回のブログポストではGolangが基本的提供する入出力パッケージであるfmtについて説明します。

  • 公式サイト: fmt

このブログポストで紹介するソースコードは下記のリンクで見ることができます。

標準出力

Golangでfmtを使う方法を調べるためmain.goファイルを生成して次のように修正します。

package main

import "fmt"

func main() {
    var a int = 10
    var b int = 20
    var f float64 = 3.14

    fmt.Print("a: ", a);
    fmt.Println("b: ", b);
    fmt.Printf("a: %d / f: %f\n", a, f);
}

プログラムを実行すると下記のような結果が表示されます。

a: 10b:  20
a: 10 / f: 3.140000

標準出力関数は下記のような特徴を持っています。

  • Print(): 関数の入力値を出力して改行をしない。
  • Println(): 関数の入力値を出力して改行をする。
  • Printf(): フォーマット(Format)に合わせて入力値を出力する。

フォーマット

Printfで使えるフォーマット(Format)は次のようです。

  • %v: データに合わせて基本の形で出力
  • %T: データタイプを出力
  • %t: boolをtrue/falseで出力
  • %d: 整数
  • %b: 2進数で出力
  • %c: ユニコード文字で出力(整数だけ可能)
  • %o: 8進数で出力
  • %O: 前に8進数であることを表示するためOoを付けて出力
  • %x: 16進数で値を出力。10以上の場合はa-fで表示
  • %X: 16진수로 값을 출력 10이상은 A-F로 표시
  • %e: 指数の形で実数を出力(実数だけ可能)
  • %E: 指数の形で実数を出力(実数だけ可能)
  • %f: 実数の値をそのまま出力(小数点6桁まで)
  • %F: 実数の値をそのまま出力
  • %g: 実数の値が大きい場合、指数の形で表示。小さい場合そのまま表示(6桁以上になると指数で表現)
  • %G: 実数の値が大きい場合、指数の形で表示。小さい場合そのまま表示
  • %s: 文字列を出力
  • %q: 特殊文字機能を使わなくそのまま文字列を出力(ex> \n, \t)

整数は次のようなフォーマットを使って並べ替えができます。

  • %5d: 5桁に合わせて出力(右揃え)
  • %05d: 5桁に合わせて出力(0が追加される)
  • %-5d: 5桁に合わせて出力(左揃え)

これを確認するため次のようにコードそ修正します。

func main() {
    a := 1
    b := 10
    c := 100
    d := 1000
    e := 10000

    fmt.Printf("a: %5d\n", a)
    fmt.Printf("b: %5d\n", b)
    fmt.Printf("c: %5d\n", c)
    fmt.Printf("d: %5d\n", d)
    fmt.Printf("e: %5d\n", e)

    fmt.Println()
    fmt.Printf("a: %05d\n", a)
    fmt.Printf("b: %05d\n", b)
    fmt.Printf("c: %05d\n", c)
    fmt.Printf("d: %05d\n", d)
    fmt.Printf("e: %05d\n", e)

    fmt.Println()
    fmt.Printf("a: %-5d\n", a)
    fmt.Printf("b: %-5d\n", b)
    fmt.Printf("c: %-5d\n", c)
    fmt.Printf("d: %-5d\n", d)
    fmt.Printf("e: %-5d\n", e)
}

このコードを実装すると下記のような結果が表示されます。

a:     1
b:    10
c:   100
d:  1000
e: 10000

a: 00001
b: 00010
c: 00100
d: 01000
e: 10000

a: 1
b: 10
c: 100
d: 1000
e: 10000

標準入力

fmtを使ってユーザの入力を貰えます。main.goファイルを次のように修正します。

package main

import "fmt"

func main() {
    var a int
    var b int

    n, err := fmt.Scanln(&a, &b)
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println(n, a, b)
    }
}

修正したプログラムを実行すると他のプログラムとは違ってプログラムが終了されなく、カーソルが画面に表示されることが確認できます。そしたら、次のように入力してみます。

10 30

上のように入力すると下記のように結果が表示されることが確認できます。

2 10 30

Scanlnはユーザから入力して貰った値をパラメータで設定されたメモリ住所に保存して、入力して貰った数とエラーがある場合エラーをリターンします。

これ以外に、ユーザの入力を受けるためfmtの関数は次のようです。

  • Scan(): 標準入力で値を入力して貰う。
  • Scanf(): 標準入力でフォーマット(Format)の形で値を入力して貰う。
  • Scanln(): 標準入力で1行を読んで値を入力する。

Scanで変数を渡す時、&を使ってメモリ住所を渡します。Scanはこのように受けたメモリ住所に入力した貰った値を保存します。

入力バッファを消す

もし、下記のようにユーザの入力を2回受けるプログラムがあるとします。

package main

import "fmt"

func main() {
    var a int
    var b int

    n, err := fmt.Scanln(&a, &b)
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println(n, a, b)
    }

    n, err = fmt.Scanln(&a, &b)
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println(n, a, b)
    }
}

当該プログラムを実行して次のように入力します。

3 a

そしたら入力した値とその値を保存する変数のタイプが違ってランタイムエラーが発生します。

expected integer

しかし、2回入力するようにプログラムを作成しましたが、2回目の入力は実行されなくエラーが発生して終了されます。

unexpected newline

これは最初エラーが発生した時、エラーが発生した時点の内容がまだバッファに保存され、そのバッファの内容がそのまま使えたので問題が発生しました。

この問題を解決するため、次のようにエラーが発生した場合、バッファを初期化する必要があります。

package main

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

func main() {
    stdin := bufio.NewReader(os.Stdin)

    var a int
    var b int

    n, err := fmt.Scanln(&a, &b)
    if err != nil {
        fmt.Println(err)
        stdin.ReadString('\n')
    } else {
        fmt.Println(n, a, b)
    }

    n, err = fmt.Scanln(&a, &b)
    if err != nil {
        fmt.Println(err)
        stdin.ReadString('\n')
    } else {
        fmt.Println(n, a, b)
    }
}

エラーが発生したら、stdin.ReadString('\n')を使って入力バッファから改行文字が出るまでバッファの内容を読んで、バッファを空にします。

完了

これでGolangの標準入出力に使えるfmtパッケージについてみてみました。入力する時はScanを使って出力する時はPrintを使いますし、入力する時、エラーが発生すると、入力バッファを空にする必要があることを勉強しました。

私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!

Posts