go語(yǔ)言生成隨機(jī)數(shù)和隨機(jī)字符串的實(shí)現(xiàn)方法
生成隨機(jī)數(shù)
隨機(jī)數(shù)的生成是計(jì)算機(jī)科學(xué)的一個(gè)研究領(lǐng)域,同時(shí)也是一種藝術(shù)。這是因?yàn)橛?jì)算機(jī)是純粹的邏輯機(jī)器,所以使用計(jì)算機(jī)生成隨機(jī)數(shù)異常困難!
你可以用 math/rand 包來(lái)生成隨機(jī)數(shù)。開(kāi)始生成隨機(jī)數(shù)之前首先需要一個(gè)種子,種子用于整個(gè)過(guò)程的初始化,它相當(dāng)重要。因?yàn)槿绻忝看味加猛瑯拥姆N子初始化,那么就總是會(huì)得到相同的隨機(jī)數(shù)序列。這意味著每個(gè)人都可以重新生成同一個(gè)序列,那這個(gè)序列就根本不能再算是隨機(jī)的了!
我們將用來(lái)生成隨機(jī)數(shù)的程序名為 randomNumbers.go,下面分成四個(gè)部分進(jìn)行介紹。這個(gè)程序需要幾個(gè)參數(shù),分別是生成隨機(jī)數(shù)的下限、生成隨機(jī)數(shù)的上限、生成隨機(jī)數(shù)的數(shù)量。如果你還用了第四個(gè)命令參數(shù),那么程序會(huì)將它作為隨機(jī)數(shù)生成器的種子。在測(cè)試的時(shí)候,你就可以再次使用這個(gè)參數(shù)生成相同的數(shù)列。
程序的第一部分如下所示:
package main import ( "fmt" "math/rand" "os" "strconv" "time" ) func random(min, max int) int { return rand.Intn(max-min) + min }
random() 函數(shù)完成了所有的工作,它通過(guò)根據(jù)指定的范圍調(diào)用 rand.Intn() 生成隨機(jī)數(shù)。
這個(gè)命令行程序的第二部分如下:
func main() { MIN := 0 MAX := 100 TOTAL := 100 SEED := time.Now().Unix() arguments := os.Args
這一部分對(duì)程序中將會(huì)用到的變量進(jìn)行了初始化。
randomNumbers.go 的第三部分包含如下的 Go 代碼:
switch len(arguments) { case 2: fmt.Println("Usage: ./randomNumbers MIN MAX TOTAL SEED") MIN, _ = strconv.Atoi(arguments[1]) MAX = MIN + 100 case 3: fmt.Println("Usage: ./randomNumbers MIN MAX TOTAL SEED") MIN, _ = strconv.Atoi(arguments[1]) MAX, _ = strconv.Atoi(arguments[2]) case 4: fmt.Println("Usage: ./randomNumbers MIN MAX TOTAL SEED") MIN, _ = strconv.Atoi(arguments[1]) MAX, _ = strconv.Atoi(arguments[2]) TOTAL, _ = strconv.Atoi(arguments[3]) case 5: MIN, _ = strconv.Atoi(arguments[1]) MAX, _ = strconv.Atoi(arguments[2]) TOTAL, _ = strconv.Atoi(arguments[3]) SEED, _ = strconv.ParseInt(arguments[4], 10, 64) default: fmt.Println("Using default values!") }
switch 代碼塊背后的邏輯相對(duì)簡(jiǎn)單:根據(jù)命令行參數(shù)的數(shù)量決定程序中的參數(shù)是使用缺省的默認(rèn)值還是使用用戶提供的值。為了簡(jiǎn)化程序,strconv.Atoi() 和 strconv.ParseInt() 函數(shù)返回的 error 參數(shù)使用下劃線字符接收,然后被忽略。如果是商業(yè)程序就千萬(wàn)不能忽略 strconv.Atoi() 和 strconv.ParseInt() 函數(shù)返回的 error 參數(shù)!
最后,使用 strconv.ParseInt() 對(duì) SEED 變量賦新的值是因?yàn)?rand.Seed() 函數(shù)要求的參數(shù)類型是 int64。strconv.ParseInt() 的第一個(gè)參數(shù)是要解析的字符串,第二個(gè)參數(shù)是輸出數(shù)的基數(shù),第三個(gè)參數(shù)是輸出數(shù)的位數(shù)。由于我們想要生成的是一個(gè) 64 位的十進(jìn)制整數(shù),所以使用 10 作為基數(shù),使用 64 作為位數(shù)。注意,如果你想解析無(wú)符號(hào)的整數(shù)的話應(yīng)該使用 strconv.ParseUint() 函數(shù)代替。
randomNumbers.go 的最后一部分是如下的 Go 代碼:
rand.Seed(SEED) for i := 0; i < TOTAL; i++ { myrand := random(MIN, MAX) fmt.Print(myrand) fmt.Print(" ") } fmt.Println() }
除了使用 Unix 時(shí)間戳作為隨機(jī)數(shù)生成器的種子,你還可以使用 /dev/random 這個(gè)系統(tǒng)設(shè)備。你可以在第 8 章“Go Unix系統(tǒng)編程”中了解 /dev/random 的相關(guān)內(nèi)容。
執(zhí)行 randomNumbers.go 將會(huì)生成如下輸出:
$ go run randomNumbers.go 75 69 15 75 62 67 64 8 73 1 83 92 7 34 8 70 22 58 38 8 54 91 65 1 50 76 5 82 61 90 10 38 40 63 6 28 51 54 49 27 52 92 76 35 44 9 66 76 90 10 29 22 20 83 33 92 80 50 62 26 19 45 56 75 40 30 97 23 87 10 43 11 42 65 80 82 25 53 27 51 99 88 53 36 37 73 52 61 4 81 71 57 30 72 51 55 62 63 79 $ go run randomNumbers.go 1 3 2 Usage: ./randomNumbers MIN MAX TOTAL SEED 1 1 $ go run randomNumbers.go 1 3 2 Usage: ./randomNumbers MIN MAX TOTAL SEED 2 2 $ go run randomNumbers.go 1 5 10 10 3 1 4 4 1 1 4 4 4 3 $ go run randomNumbers.go 1 5 10 10 3 1 4 4 1 1 4 4 4 3
如果你對(duì)隨機(jī)數(shù)生成真的很有興趣,那么你應(yīng)該先讀一下 Donald E.Knuth 寫的 The Art of Computer Programming (Addison-Wesley Professional, 2011) 的第二卷。
如果需要用 Go 生成更安全的隨機(jī)數(shù)的話,你可以使用 crypto/rand 包。這個(gè)包中實(shí)現(xiàn)了滿足密碼學(xué)安全的偽隨機(jī)數(shù)生成器。你可以在 https://golang.org/pkg/crypto/rand/ 文檔頁(yè)面了解更多關(guān)于 crypto/rand 包的信息。
生成隨機(jī)字符串
一旦你知道了計(jì)算機(jī)是如何呈現(xiàn)出單個(gè)字符,從隨機(jī)數(shù)過(guò)渡到隨機(jī)字符串就不難了。這一節(jié)將會(huì)介紹如何使用前一節(jié)中 randomNumbers.go 的代碼生成難以猜出的密碼。用于完成這個(gè)任務(wù)的 Go 程序叫做 generatePassword.go,下面將分四個(gè)部分進(jìn)行介紹。這個(gè)程序只需要一個(gè)命令行參數(shù),就是你需要生成的密碼的長(zhǎng)度。
generatePassword.go 的第一部分包含如下的 Go 代碼:
package main import ( "fmt" "math/rand" "os" "strconv" "time" ) func random(min, max int) int { return rand.Intn(max-min) + min }
generatePassword.go 的第二個(gè)代碼段如下:
func main() { MIN := 0 MAX := 94 SEED := time.Now().Unix() var LENGTH int64 = 8 arguments := os.Arg
我們只想得到可打印的 ASCII 字符,所以對(duì)生成隨機(jī)數(shù)的范圍進(jìn)行了限制。ASCII 字符表中可打印的字符一共有 94 個(gè)。這意味著該程序生成的隨機(jī)數(shù)的范圍應(yīng)該是從 0 到 94 且不包括 94。
generatePassword.go 的第三個(gè)代碼段如下:
switch len(arguments) { case 2: LENGTH, _ = strconv.ParseInt(os.Args[1], 10, 64) default: fmt.Println("Using default values!") } rand.Seed(SEED)
generatePassword.go 的最后一部分如下:
startChar := "!" var i int64 = 1 for { myRand := random(MIN, MAX) newChar := string(startChar[0] + byte(myRand)) fmt.Print(newChar) if i == LENGTH { break } i++ } fmt.Println() }
startChar 參數(shù)保存了這個(gè)程序可以生成的第一個(gè) ASCII 字符,也就是十進(jìn)制 ASCII 值為 33 的感嘆號(hào)。已知該程序生成的隨機(jī)數(shù)小于 94,可以計(jì)算出生成的最大的 ASCII 值為 93 + 33,等于 126,也就是 ~ 的 ASCII 值。下面的輸出是含有十進(jìn)制數(shù)值的 ASCII 字符表:
The decimal set:
? 0 nul??? 1 soh??? 2 stx??? 3 etx??? 4 eot??? 5 enq??? 6 ack??? 7 bel
? 8 bs???? 9 ht??? 10 nl??? 11 vt??? 12 np??? 13 cr??? 14 so??? 15 si
?16 dle?? 17 dc1?? 18 dc2?? 19 dc3?? 20 dc4?? 21 nak?? 22 syn?? 23 etb
?24 can?? 25 em??? 26 sub?? 27 esc?? 28 fs??? 29 gs??? 30 rs??? 31 us
?32 sp??? 33? !??? 34? "??? 35? #??? 36? $??? 37? %??? 38? &??? 39? '
?40? (??? 41? )??? 42? *??? 43? +??? 44? ,??? 45? -??? 46? .??? 47? /
?48? 0??? 49? 1??? 50? 2??? 51? 3??? 52? 4??? 53? 5??? 54? 6??? 55? 7
?56? 8??? 57? 9??? 58? :??? 59? ;??? 60? <??? 61? =??? 62? >??? 63? ?
?64? @??? 65? A??? 66? B??? 67? C??? 68? D??? 69? E??? 70? F??? 71? G
?72? H??? 73? I??? 74? J??? 75? K??? 76? L??? 77? M??? 78? N??? 79? O
?80? P??? 81? Q??? 82? R??? 83? S??? 84? T??? 85? U??? 86? V??? 87? W
?88? X??? 89? Y??? 90? Z??? 91? [??? 92? \??? 93? ]??? 94? ^??? 95? _
?96? `??? 97? a??? 98? b??? 99? c?? 100? d?? 101? e?? 102? f?? 103? g
104? h?? 105? i?? 106? j?? 107? k?? 108? l?? 109? m?? 110? n?? 111? o
112? p?? 113? q?? 114? r?? 115? s?? 116? t?? 117? u?? 118? v?? 119? w
120? x?? 121? y?? 122? z?? 123? {?? 124? |?? 125? }?? 126? ~?? 127 del
在你最喜歡的 Unix shell 中輸入 man ascii 就能生成易讀的 ASCII 字符表。
執(zhí)行 generatePassword.go 并傳入合適的命令行參數(shù)將生成如下輸出:
$ go run generatePassword.go Using default values! ugs$5mv1 $ go run generatePassword.go Using default values! PA/8hA@? $ go run generatePassword.go 20 HBR+=3\UA'B@ExT4QG|o $ go run generatePassword.go 20 XLcr|R{*pX/::'t2u^T'
到此這篇關(guān)于go語(yǔ)言生成隨機(jī)數(shù)和隨機(jī)字符串的實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)go語(yǔ)言生成隨機(jī)數(shù)和隨機(jī)字符串內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang簡(jiǎn)單獲取上傳文件大小的實(shí)現(xiàn)代碼
這篇文章主要介紹了golang簡(jiǎn)單獲取上傳文件大小的方法,涉及Go語(yǔ)言文件傳輸及文件屬性操作的相關(guān)技巧,需要的朋友可以參考下2016-07-07關(guān)于升級(jí)go1.18的goland問(wèn)題詳解
作為一個(gè)go語(yǔ)言程序員,覺(jué)得自己有義務(wù)為go新手開(kāi)一條更簡(jiǎn)單便捷的上手之路,下面這篇文章主要給大家介紹了關(guān)于升級(jí)go1.18的goland問(wèn)題的相關(guān)資料,需要的朋友可以參考下2022-11-11詳解Go語(yǔ)言中泛型的實(shí)現(xiàn)原理與使用
本文是對(duì)泛型的基本思想及其在?Go?中的實(shí)現(xiàn)的一個(gè)比較容易理解的介紹,同時(shí)也是對(duì)圍繞泛型的各種性能討論的簡(jiǎn)單總結(jié),感興趣的可以學(xué)習(xí)一下2022-05-05golang通過(guò)context控制并發(fā)的應(yīng)用場(chǎng)景實(shí)現(xiàn)
這篇文章主要介紹了golang通過(guò)context控制并發(fā)的應(yīng)用場(chǎng)景實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01