[Golang] Generate Random String From [a-z0-9]


Lesson learned from this exercise

  1. Give seed value to the Seed func in math/rand package. Otherwise the same string is returned on every time.

  2. Accoding to the comment from @dchapes, the pseudorandom number generator should not be re-seeded on each use, nor re-seed the global PRNG in a package. @shurcooL shows how to properly seed the PRNG:

    If you're using global rand.Rand, don't re-seed it. But if you want to set your own seed, create your own local instance of rand.Rand.

    var r *rand.Rand // Rand for this package.
    
    func init() {
            r = rand.New(rand.NewSource(time.Now().UnixNano()))
    }
    
    func RandomString(strlen int) string {
            // use existing r, no need to re-seed it
            r.Intn(len(chars))
    }
    

    You can also simplify this into one line:

    // r is a source of random numbers used in this package.
    var r = rand.New(rand.NewSource(time.Now().UnixNano()))
    
  3. Allocate the byte array with make function.

    Correct:

    result := make([]byte, strlen)
    

    Wrong:

    var result [strlen]byte
    
  4. Covert the []byte to string by built-in string keyword.

Souce Code

Run code on Go Playground

(Note that time package in Go Playground always returns the same value no matter what current time is, so the generated string will always be the same on Go Playground)

a-z0-9.go | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package mylib

import (
	"math/rand"
	"time"
)

var r *rand.Rand // Rand for this package.

func init() {
	r = rand.New(rand.NewSource(time.Now().UnixNano()))
}

func RandomString(strlen int) string {
	const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
	result := make([]byte, strlen)
	for i := range result {
		result[i] = chars[r.Intn(len(chars))]
	}
	return string(result)
}

Appendix

Another way to generate string without make keyword:

Run code on Go Playground

rdnstr.go | repository | view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package mylib

import (
	"math/rand"
	"time"
)

var r *rand.Rand // Rand for this package.

func init() {
	r = rand.New(rand.NewSource(time.Now().UnixNano()))
}

func RandomString2(strlen int) string {
	const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
	result := ""
	for i := 0; i < strlen; i++ {
		index := r.Intn(len(chars))
		result += chars[index : index+1]
	}
	return result
}