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 パッケージを使っています。スライスから取り出す要素番号(0〜2)をランダムに決めるために使用しています。
  • 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)
}

アプリケーション実行

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

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

$ go run .
Hi, genzouw. Welcome!

$ go run .
Great to see you, genzouw!

$ go run .
Hail, genzouw! Well met!

ひとこと

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

Posted by genzouw