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:
- Generating Random Integers: Using rand.Intn and rand.Int63.
- Generating Random Floats: Using rand.Float64 and creating ranges.
- Generating Random Booleans: Converting random integers to booleans.
- Generating Random Strings: Creating a helper function for random strings.
- Seeding the Random Generator: Using rand.Seed to avoid repetitive sequences.
- Generating Cryptographically Secure Random Values: Using crypto/rand for secure applications.
- 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.