golang 字符串随机数
While completely random is not really possible, we still can have pseudorandom numbers on computers.
尽管不可能完全随机 ,但我们仍然可以在计算机上使用伪随机数。
We can have regular pseudorandom numbers, and cryprographically secure pseudorandom numbers.
我们可以有规则的伪随机数,也可以有安全的伪随机数。
Let’s see how to that in Go.
让我们看看如何在Go中做到这一点。
伪随机数 (Pseudorandom numbers)
The math/rand
package provided by the Go Standard Library gives us pseudo-random number generators (PRNG), also called deterministic random bit generators.
Go标准库提供的math/rand
软件包为我们提供了伪随机数生成器(PRNG) ,也称为确定性随机位生成器 。
As with all pseudo number generators, any number generated through math/rand
is not really random by default, as being deterministic it will always print the same value each time.
与所有伪数字生成器一样,默认情况下,通过math/rand
生成的任何数字都不是真正随机的,因为具有确定性,它将始终每次打印相同的值 。
As an example, try running this code which introduces rand.Intn(n)
, which returns a random number between 0
and n - 1
.
例如,请尝试运行引入rand.Intn(n)
代码,该代码返回0
到n - 1
之间的随机数。
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
}
You’ll always see the same sequence every time you run the program. The random number changes inside the program, but every time you run it, you’ll get the same output:
每次运行该程序时,您总是会看到相同的顺序。 随机数在程序内部会发生变化,但是每次运行它时,您都会得到相同的输出:
11
27
17
29
1
This is because by default the seed is always the same, the number 1
. To actually get a random number, you need to provide a unique seed for your program. You really want to not forget seeding, and instead properly seed our pseudonumber generator. How?
这是因为默认情况下,种子始终是相同的,即数字1
。 要实际获得随机数,您需要为程序提供唯一的种子 。 您确实不希望忘记播种,而是适当地为我们的伪数生成器播种。 怎么样?
Use rand.Seed()
before calling any math/rand
method, passing an int64
value. You just need to seed once in your program, not every time you need a random number. The most used seed is the current time, converted to int64
by UnixNano with rand.Seed(time.Now().UnixNano())
:
在调用任何math/rand
方法并传递int64
值之前,请使用rand.Seed()
。 您只需要在程序中播种一次,而不是每次都需要一个随机数。 最常用的种子是当前时间,由UnixNano使用rand.Seed(time.Now().UnixNano())
转换为int64
:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
fmt.Println(rand.Intn(30))
}
Remember that due to its sandboxing, the Go Playground always begins with the same time, so this code won’t work as expected. Try it on a real environment, and the numbers that previosly didn’t change, they will now print differently each time you run the program.
请记住,由于其沙箱操作,Go Playground总是在同一时间开始,因此此代码无法按预期工作。 在实际环境中进行尝试,并且以前不会更改的数字现在会在每次运行程序时以不同的方式显示。
Some common examples are listed below for ease of reuse:
下面列出了一些常见示例,以方便重用:
产生一个随机整数 (Generate a random integer)
package main
import (
"fmt"
"math/rand"
"time"
)
// Returns an int >= min, < max
func randomInt(min, max int) int {
return min + rand.Intn(max-min)
}
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println(randomInt(1, 11)) //get an int in the 1...10 range
}
产生随机字串 (Generate a random string)
package main
import (
"fmt"
"math/rand"
"time"
)
// Returns an int >= min, < max
func randomInt(min, max int) int {
return min + rand.Intn(max-min)
}
// Generate a random string of A-Z chars with len = l
func randomString(len int) string {
bytes := make([]byte, len)
for i := 0; i < len; i++ {
bytes[i] = byte(randomInt(65, 90))
}
return string(bytes)
}
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println(randomString(10)) // print 10 chars
}
Will return 10 chars in uppercase format. Change
将以大写格式返回10个字符。 更改
bytes[i] = byte(randomInt(65, 90))
to
至
bytes[i] = byte(randomInt(97, 122))
for just lowercase.
小写。
If you instead want to have a pool of specific chars to pick from, use
如果您想从中选择特定的字符池,请使用
package main
import (
"fmt"
"math/rand"
"time"
)
var pool = "_:$%&/()"
// Generate a random string of A-Z chars with len = l
func randomString(l int) string {
bytes := make([]byte, l)
for i := 0; i < l; i++ {
bytes[i] = pool[rand.Intn(len(pool))]
}
return string(bytes)
}
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println(randomString(1000))
}
Change len(pool)
to utf8.RuneCountInString(pool)
if you use non-ascii strings, as len()
counts the bytes, but not all chars take just one byte in Unicode - see https://stackoverflow.com/questions/12668681/how-to-get-the-number-of-characters-in-a-string.
如果您使用非ascii字符串,请将len(pool)
更改为utf8.RuneCountInString(pool)
,因为len()
计算字节数,但并非所有字符都只占用Unicode中的一个字节-请参阅https://stackoverflow.com/questions/ 12668681 /如何获取字符串中的字符数 。
生成随机整数数组 (Generate a random array of integers)
package main
import (
"fmt"
"math/rand"
"time"
)
func randomArray(len int) []int {
a := make([]int, len)
for i := 0; i <= len-1; i++ {
a[i] = rand.Intn(len)
}
return a
}
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println(randomArray(10))
}
加密级随机数 (Crypto-level random numbers)
Go also provides a Cryptographically secure pseudorandom number generator (CSPRNG) in the standard library package crypto.rand
Go还提供了标准库包crypto.rand
的加密安全伪随机数生成器(CSPRNG) 。
So you might question, why should I even use the pseudo-number random generator library provided by math/rand
instead? Well, it depends on the use case. math/rand
is much faster for applications that don’t need crypto-level or security-related random data generation. crypto.rand
is suited for secure and crypto-ready usage, but it’s slower.
因此,您可能会问,为什么我什至要使用math/rand
提供的伪数随机生成器库呢? 好吧,这取决于用例。 对于不需要加密级别或与安全相关的随机数据生成的应用程序, math/rand
更快 。 crypto.rand
适用于安全且可加密的使用,但速度较慢。
What it should be used for? For example, generating passwords, CSRF tokens, session keys, or anything remotely related to security.
它应该用于什么? 例如,生成密码,CSRF令牌,会话密钥或与安全性远程相关的任何内容。
It does not rely on the current time, like we did in the previous examples in math/rand
, but instead it uses the operating system CSPRNG APIs: the CryptGenRandom API on Windows, and /dev/urandom/
on all the others (Linux, OSX, *nix)
它不依赖当前时间,就像我们在上面的math/rand
示例中所做的那样,而是使用操作系统CSPRNG API:Windows上的CryptGenRandom API,其他所有上的( /dev/urandom/
(Linux, OSX,* nix)
You get 256 random bytes directly with
您直接获得256个随机字节
package main
import (
"crypto/rand"
"fmt"
)
func main() {
key := [256]byte{}
_, err := rand.Read(key[:])
if err != nil {
panic(err)
}
fmt.Println(key)
}
I’m taking a code sample from Matt Silverlock: you can make it more general and create a random bytes generation function
我正在从Matt Silverlock中获取代码示例:您可以使其更通用并创建随机字节生成函数
// GenerateRandomBytes returns securely generated random bytes.
// It will return an error if the system's secure random
// number generator fails to function correctly, in which
// case the caller should not continue.
func GenerateRandomBytes(n int) ([]byte, error) {
b := make([]byte, n)
_, err := rand.Read(b)
// Note that err == nil only if we read len(b) bytes.
if err != nil {
return nil, err
}
return b, nil
}
and using this, a random string generation function,
并使用它,一个随机字符串生成函数,
// GenerateRandomString returns a URL-safe, base64 encoded
// securely generated random string.
// It will return an error if the system's secure random
// number generator fails to function correctly, in which
// case the caller should not continue.
func GenerateRandomString(s int) (string, error) {
b, err := GenerateRandomBytes(s)
return base64.URLEncoding.EncodeToString(b), err
}
golang 字符串随机数