目錄

Random

如果要產生假資料的話,亂數產生器是必要的。

今天先建立一個中文字的資料結構,然後再由 Go 產生亂數來選擇中文字,最後再經由 Command 輸出。

首先要了解亂數是怎麼產生的,查了一下資料,看來 math/rand 就夠用了。

因為要給種子,所以查了一下時間 time 微秒的取法,結果找到奈秒的:

t := time.Now().UnixNano()

fmt.Println(t)

另外官方範例有展示 math/rand 的兩種用法,一種是全域的:

rand.Seed(time.Now().UnixNano())

fmt.Println(rand.Int())

另一種是用種子取得結構後,再開始產生亂數:

t := time.Now().UnixNano()
r1 := rand.New(rand.NewSource(t))
r2 := rand.New(rand.NewSource(t))

fmt.Println(r1.Int())
fmt.Println(r1.Int())
fmt.Println(r1.Int())
fmt.Println(r2.Int())
fmt.Println(r2.Int())
fmt.Println(r2.Int())

輸出如下:

6097576665619044690
3051760752526126731
1042372804046134795
6097576665619044690
3051760752526126731
1042372804046134795

亂數看來沒問題了,再來可以建一個模組存放這些中文的靜態資料。

首先建目錄 provider,在下面先建資源檔 resource.go

package provider

var names = []string{
	"金太郎",
	"金城武",
	"金智賢",
}

這個檔比較沒什麼問題,下一個建主要產生器 generator

package provider

import (
	"math/rand"
	"time"
)

type Generator struct {
	rand *rand.Rand
}

func (generator *Generator) Name() string {
	length := len(names)

	return names[generator.rand.Intn(length)]
}

func Create() Generator {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))

	return Generator{
		rand: r,
	}
}

這裡說明一下,Create() 是建立 Generator 結構,類似工廠方法。

Generator 則有著亂數產生器,可以自行建立亂數,也可以依亂數取得資源內的內容。

其中 rand.Intn(length) 會回傳 0 ~ length 中的一個數字。剛好可以拿來當 key。

原始碼的 Action 函式如下:

func(c *cli.Context) error {
    num, err := strconv.Atoi(c.String("num"))

    if err != nil {
        return err
    }

    fmt.Println("Generate " + strconv.Itoa(num))

    generator := provider.Create()

    for i := 0; i < num; i++ {
        fmt.Println(generator.Name())
    }

    return nil
},

使用 go run 執行:

$ go run main.go generate
Generate 10
金城武
金太郎
金智賢
金智賢
金智賢
金太郎
金智賢
金智賢
金智賢
金太郎

詳細程式可以參考 PR Day 18