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

はじめに

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

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

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

スライス ( slice ) とは?

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

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

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

コーディング開始

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

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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))]
}

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
$ 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 を開き、 コードを変更

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
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 モジュールの配置されているディレクトリで、コードを実行してみます。

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

1
2
3
4
5
6
7
8
$ go run .
Hi, genzouw. Welcome!

$ go run .
Great to see you, genzouw!

$ go run .
Hail, genzouw! Well met!

ひとこと

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