Home Go Tutorial on Generating Random Values in Go

Tutorial on Generating Random Values in Go

In Go, you can generate random values using the math/rand package.

The rand package provides functions for generating random numbers, strings, and other types, which are essential for tasks like simulations, testing, and creating unique identifiers.

In this tutorial, we’ll cover:

1. Generating Random Integers

The rand package provides several functions for generating random integers. You can use rand.Intn to generate random numbers within a specified range.

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    // Generate a random integer between 0 and 99
    randInt := rand.Intn(100)
    fmt.Println("Random integer between 0 and 99:", randInt)

    // Generate a random integer of arbitrary size
    randInt64 := rand.Int63()
    fmt.Println("Random int64:", randInt64)
}

Output (sample):

Random integer between 0 and 99: 42
Random int64: 859014124579

In this example:

  • rand.Intn(100) generates a random integer from 0 to 99.
  • rand.Int63() generates a random int64 value across the full range of 63-bit integers.

Note: The default seed for rand is the same each time the program runs, so the results will be consistent without additional seeding.

2. Generating Random Floats

The rand package provides functions for generating random floating-point numbers between 0.0 and 1.0, or within a specified range.

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    // Generate a random float64 between 0.0 and 1.0
    randFloat := rand.Float64()
    fmt.Println("Random float64 between 0.0 and 1.0:", randFloat)

    // Generate a random float32 between 0.0 and 1.0
    randFloat32 := rand.Float32()
    fmt.Println("Random float32 between 0.0 and 1.0:", randFloat32)

    // Generate a random float between a specified range
    min, max := 5.0, 10.0
    randFloatInRange := min + rand.Float64()*(max-min)
    fmt.Println("Random float64 between 5.0 and 10.0:", randFloatInRange)
}

Output (sample):

Random float64 between 0.0 and 1.0: 0.743
Random float32 between 0.0 and 1.0: 0.247
Random float64 between 5.0 and 10.0: 7.654

In this example:

  • rand.Float64() generates a float64 between 0.0 and 1.0.
  • rand.Float32() generates a float32 between 0.0 and 1.0.
  • min + rand.Float64()*(max-min) generates a random float in the specified range (in this case, between 5.0 and 10.0).

3. Generating Random Booleans

You can generate a random boolean by checking if a random integer is even or odd.

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    randBool := rand.Intn(2) == 1
    fmt.Println("Random boolean:", randBool)
}

Output (sample):

Random boolean: true

In this example:

  • rand.Intn(2) == 1 generates true or false based on whether the random integer is 1 or 0.

4. Generating Random Strings

To generate a random string, you can create a helper function that selects random characters from a specified character set.

package main

import (
    "fmt"
    "math/rand"
    "time"
)

const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

func randomString(length int) string {
    rand.Seed(time.Now().UnixNano())
    b := make([]byte, length)
    for i := range b {
        b[i] = charset[rand.Intn(len(charset))]
    }
    return string(b)
}

func main() {
    fmt.Println("Random string:", randomString(10))
}

Output (sample):

Random string: H3aGZ1mQxK

In this example:

  • randomString generates a random string of specified length by selecting characters from charset.
  • rand.Intn(len(charset)) randomly indexes into the character set to create each character in the string.

5. Seeding the Random Generator for Unique Sequences

The rand.Seed function seeds the random number generator with a specified value. Seeding with the current time ensures unique sequences each time the program runs.

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    // Seed with current time for unique random values
    rand.Seed(time.Now().UnixNano())

    fmt.Println("Random int:", rand.Intn(100))
    fmt.Println("Another random int:", rand.Intn(100))
}

Output (sample):

Random int: 57
Another random int: 23

In this example:

  • rand.Seed(time.Now().UnixNano()) initializes the random generator with the current time in nanoseconds, ensuring unique random sequences each time the program runs.

6. Generating Cryptographically Secure Random Values

The crypto/rand package provides cryptographically secure random values, suitable for security-sensitive applications, like generating tokens and passwords.

Generating a Random Byte Slice

package main

import (
    "crypto/rand"
    "fmt"
    "log"
)

func secureRandomBytes(length int) ([]byte, error) {
    b := make([]byte, length)
    _, err := rand.Read(b)
    if err != nil {
        return nil, err
    }
    return b, nil
}

func main() {
    bytes, err := secureRandomBytes(16)
    if err != nil {
        log.Fatal("Error generating secure random bytes:", err)
    }
    fmt.Println("Secure random bytes:", bytes)
}

Output (sample):

Secure random bytes: [105 229 72 32 239 21 88 91 126 233 49 191 34 196 221 10]

In this example:

  • crypto/rand.Read(b) fills the byte slice b with secure random bytes.
  • The result is suitable for cryptographic purposes but requires error handling, as rand.Read may fail.

Generating a Secure Random String

package main

import (
    "crypto/rand"
    "fmt"
    "math/big"
)

const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

func secureRandomString(length int) (string, error) {
    result := make([]byte, length)
    for i := range result {
        n, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
        if err != nil {
            return "", err
        }
        result[i] = charset[n.Int64()]
    }
    return string(result), nil
}

func main() {
    str, err := secureRandomString(12)
    if err != nil {
        fmt.Println("Error generating secure random string:", err)
    }
    fmt.Println("Secure random string:", str)
}

Output (sample):

Secure random string: X3aK8vQzR2Wp

In this example:

  • rand.Int(rand.Reader, big.NewInt(int64(len(charset)))) generates a secure random index in charset.
  • This approach ensures each character is chosen securely, making it suitable for sensitive data like passwords or tokens.

7. Best Practices for Generating Random Values in Go

a) Use rand.Seed for Non-Cryptographic Random Values

To get unique random values across program runs, initialize the seed once at the beginning of the program. If your application doesn’t need secure randomness, math/rand is suitable.

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

b) Use crypto/rand for Secure Randomness

When generating values for sensitive data (like passwords, tokens, or keys), use crypto/rand to ensure security.

rand.Read(byteSlice) // Fills a byte slice with secure random values

c) Avoid Re-Seeding Multiple Times

In non-cryptographic contexts, only seed the random generator once at the start of the program to avoid repeating random sequences within a single run.

d) Generate Secure Strings Using big.Int and crypto/rand

For security-sensitive applications, use crypto/rand with math/big to safely index into character sets.

n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))

Summary

In this tutorial, we covered various methods for generating random values in Go:

  1. Generating Random Integers: Using rand.Intn and rand.Int63.
  2. Generating Random Floats: Using rand.Float64 and creating ranges.
  3. Generating Random Booleans: Converting random integers to booleans.
  4. Generating Random Strings: Creating a helper function for random strings.
  5. Seeding the Random Generator: Using rand.Seed to avoid repetitive sequences.
  6. Generating Cryptographically Secure Random Values: Using crypto/rand for secure applications.
  7. Best Practices: Guidelines for generating random values effectively and securely.

By following these techniques, you can generate random values in Go for a variety of applications, from simple simulations to secure, cryptographic needs.

You may also like