Go 言語でランダムな文字列を返却する( `math/rand` ライブラリ )

はじめに

今回は、 いままで作成した greetings モジュール を変更し、 毎回同じ文字列を返却する仕組み だったものから、 事前に登録されていたいくつかの挨拶文字列からランダムで 1 つ選び返却する仕組み にします。

当エントリは以下のエントリの続きとなっています。事前に一読しておくことをおすすめします。

今回の仕組みを実現するために、 Go 言語に用意されている スライス(slice) という組み込み型を利用します。

スライス(slice) とは?

配列(array) に似ている組み込み型です。

配列 は格納できる要素数が固定です。
スライス は要素を追加したり削除された場合に動的にサイズが変更される配列です。
Go 言語における便利な組み込み型の一つです。

他のエントリでスライスについて詳しく取り上げてみましたので、是非参考ください!

コーディング開始

ここでは、挨拶文言を 3 つ用意し、スライスに格納しておくことにしましょう。
このスライスからランダムに要素を選び、関数の戻り値に利用します。

1. greetings/greetings.go を開き、コードを変更

package greetings

import (
    "errors"
    "fmt"
    "math/rand"
    "time"
)

func Hello(name string) (string, error) {
    if name == "" {
        return "", errors.New("empty name")
    }

    message := fmt.Sprintf(randomFormat(), name)

    return message, nil
}

func init() {
    rand.Seed(time.Now().UnixNano())
}

func randomFormat() string {
    formats := []string{
        "Hi, %v. Welcome!",
        "Great to see you, %v!",
        "Hail, %v! Well met!",
    }

    return formats[rand.Intn(len(formats))]
}

前回からの差分は以下になります。

$ git diff
diff --git greetings.go greetings.go
index 1e584b1..9cde4e7 100644
--- greetings.go
+++ greetings.go
@@ -3,6 +3,8 @@ package greetings
 import (
        "errors"
        "fmt"
+       "math/rand"
+       "time"
 )

 func Hello(name string) (string, error) {
@@ -10,7 +12,21 @@ func Hello(name string) (string, error) {
                return "", errors.New("empty name")
        }

-       message := fmt.Sprintf("Hi, %v. Welcome!", name)
+       message := fmt.Sprintf(randomFormat(), name)

        return message, nil
 }
+
+func init() {
+       rand.Seed(time.Now().UnixNano())
+}
+
+func randomFormat() string {
+       formats := []string{
+               "Hi, %v. Welcome!",
+               "Great to see you, %v!",
+               "Hail, %v! Well met!",
+       }
+
+       return formats[rand.Intn(len(formats))]
+}

コード解説

かんたんに解説します。

  • randomFormat 関数を追加。
    • 挨拶文言をランダムで 1 つ返却。
    • 関数名の先頭が小文字で始まっていることに注目!自身のパッケージ内でしか呼び出せない関数を表しています。
  • randomFormat 関数の中では、 foramts というスライスを宣言し 3 つの文字列を格納しています。
    • スライスは配列と異なり、サイズ指定を省略できます。
  • math/rand パッケージを使っています。スライスから取り出す要素番号(1〜3)をランダムに決めるために使用しています。
  • init 関数を追加し、 rand 関数のシード(種)を設定しています。
    • Go では、プログラム開始時に init 関数が自動的に実行されます。
    • その後、グローバル変数の初期化が行われます。
  • Hello 関数の中では、 randomFormat 関数が呼び出されます。実行結果の文字列から %v の値をパラメータで変換し、返却します。

2. hello/hello.go を開き、 コードを変更

package main

import (
    "fmt"
    "log"

    "genzouw/greetings"
)

func main() {
    log.SetPrefix("greetings: ")
    log.SetFlags(0)

    message, err := greetings.Hello("genzouw")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(message)
}

前回からの差分は以下になります。

$ go run .
Hail, genzouw! Well met!

11:28:01 in ~/hello on  master [!+] workplace-development-cluster (workplace)  GCP=workplace-development-307400
$ go run .
Hi, genzouw. Welcome!

11:28:03 in ~/hello on  master [!+] workplace-development-cluster (workplace)  GCP=workplace-development-307400
$ go run .
Great to see you, genzouw!

アプリケーション実行

hello モジュールの配置されているディレクトリで、コードを実行してみます。

何度か実行してみると、挨拶文言が異なっているはずです。(同じ文言が連続して出力されることもあります。)

$ go run .
Hi, genzouw. Welcome!

$ go run .
Great to see you, genzouw!

$ go run .
Hail, genzouw! Well met!

ひとこと

次回は Key-Valueの仕組みを使って、複数の人々に挨拶文を返却 してみます。

Posted by genzouw