Generate random numbers and strings in Go

in spite ofCompletely random is impossible, We can still use pseudo-random numbers on the computer.

We can haveRegularPseudo-random numbers, andRadiologically safePseudo random number.

Let's see how to do this in Go.

Pseudo random number

Thismath/randpackageThe content provided by the Go standard library allows usPseudo Random Number Generator (PRNG), is also calledDeterministic Random Bit Generator.

As with all pseudo-digital generators, throughmath/randYesNot very randomDeterministic by defaultWill print the same value every time.

For example, try running this code, which describesrand.Intn(n), Returns a random number in between0withn - 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)) }

playground

You will always see the same sequence every time you run the program. The random number will change inside the program, but every time you run it, you will get the same output:

11
27
17
29
1

This is because by default, the seed is always the same, which is the number1. To actually obtain a random number, you need to provide a uniqueseedFor your program. You really don’t want to forget to seed, but to seed our pseudo-number generator correctly. how is it?

userand.Seed()Before calling anyonemath/randMethod throughint64value. You only need to seed the program once, instead of requiring a random number each time. The most commonly used seed is the current time, converted toint64afterUnix Nanowithrand.Seed(time.Now().UnixNano()):

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)) }

Keep in mind that due to its sandbox operation, Go Playground always starts at the same time, so this code does not work as expected. Try it in a real environment, and the numbers that have not changed before will now be printed differently every time you run the program.

Some common examples are listed below to facilitate 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 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 characters in uppercase format. change

bytes[i] = byte(randomInt(65, 90))

To

bytes[i] = byte(randomInt(97, 122))

Lower case only.

If you want to select a specific character pool from it, please 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)) }

changelen(pool)Toutf8.RuneCountInString(pool)If you use a non-ascii string, it islen()Count the number of bytes, but not all characters occupy only one byte in Unicode-seehttps://stackoverflow.com/questions/12668681/how-to-get-the-number-of-characters-in-a-string.

Generate random integer array

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)) }

Encryption level random number

To also provideCryptographically Secure Pseudo Random Number Generator (CSPRNG)In the standard library packagecrypto.rand

So you may ask, why should I use the pseudo-random generator library provided by it?math/randinstead? Well, it depends on the use case.math/randYesMuch fasterSuitable for applications that do not require encryption levels or random data generation related to security.crypto.randSuitable for safe and encryptable purposes, but the speed is slower.

What should it be used for? For example, generating passwords, CSRF tokens, session keys or anything related to security remote.

It does not depend on the current time, as we did in the previous examplemath/rand, But use the operating system CSPRNG API: CryptGenRandom API on Windows and/dev/urandom/On all other versions (Linux, OSX, *nix)

You get 256 random bytes directly

package main

import ( “crypto/rand” “fmt” )

func main() { key := [256]byte{} _, err := rand.Read(key[:]) if err != nil { panic(err) } fmt.Println(key) }

I am getting code samples fromMatt Silverlock: You can make it more versatile and create a random byte generation function

// 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
    }
<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">b</span>, <span style="color:#66d9ef">nil</span>

}

And use it, 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
}

More tutorials: