Book Image

Mastering Go – Third Edition - Third Edition

By : Mihalis Tsoukalos
5 (2)
Book Image

Mastering Go – Third Edition - Third Edition

5 (2)
By: Mihalis Tsoukalos

Overview of this book

Mastering Go is the essential guide to putting Go to work on real production systems. This freshly updated third edition includes topics like creating RESTful servers and clients, understanding Go generics, and developing gRPC servers and clients. Mastering Go was written for programmers who want to explore the capabilities of Go in practice. As you work your way through the chapters, you’ll gain confidence and a deep understanding of advanced Go concepts, including concurrency and the operation of the Go Garbage Collector, using Go with Docker, writing powerful command-line utilities, working with JavaScript Object Notation (JSON) data, and interacting with databases. You’ll also improve your understanding of Go internals to optimize Go code and use data types and data structures in new and unexpected ways. This essential Go programming book will also take you through the nuances and idioms of Go with exercises and resources to fully embed your newly acquired knowledge. With the help of Mastering Go, you’ll become an expert Go programmer by building Go systems and implementing advanced Go techniques in your projects.
Table of Contents (17 chapters)
14
Other Books You May Enjoy
15
Index

Generating random numbers

Random number generation is an art as well as a research area in computer science. This is because computers are purely logical machines, and it turns out that using them to generate random numbers is extremely difficult! Go can help you with that using the functionality of the math/rand package. Each random number generator needs a seed to start producing numbers. The seed is used for initializing the entire process and is extremely important because if you always start with the same seed, you will always get the same sequence of pseudo-random numbers. This means that everybody can regenerate that sequence, and that particular sequence will not be random after all. However, this feature is really useful for testing purposes. In Go, the rand.Seed() function is used for initializing a random number generator.

If you are really interested in random number generation, you should start by reading the second volume of The Art of Computer Programming by Donald E. Knuth (Addison-Wesley Professional, 2011).

The following function, which is part of randomNumbers.go found in ch02 in the book's GitHub repository, is what generates random numbers in the [min, max) range.

func random(min, max int) int {
    return rand.Intn(max-min) + min
}

The random() function does all of the work, which is generating pseudo-random numbers in a given range from min to max-1 by calling rand.Intn(). rand.Intn() generates non-negative random integers from 0 up to the value of its single parameter minus 1.

The randomNumbers.go utility accepts four command-line parameters but can also work with fewer parameters by using default values. By default, randomNumbers.go produces 100 random integers from 0 up to and including 99.

$ go run randomNumbers.go 
Using default values!
39 75 78 89 39 28 37 96 93 42 60 69 50 9 69 27 22 63 4 68 56 23 54 14 93 61 19 13 83 72 87 29 4 45 75 53 41 76 84 51 62 68 37 11 83 20 63 58 12 50 8 31 14 87 13 97 17 60 51 56 21 68 32 41 79 13 79 59 95 56 24 83 53 62 97 88 67 59 49 65 79 10 51 73 48 58 48 27 30 88 19 16 16 11 35 45 72 51 41 28

In the next output, we define each of the parameters manually (the last parameter of the utility is the seed value):

$ go run randomNumbers.go 1 5 10 10
3 1 4 4 1 1 4 4 4 3
$ go run randomNumbers.go 1 5 10 10
3 1 4 4 1 1 4 4 4 3
$ go run randomNumbers.go 1 5 10 11
1 4 2 1 3 2 2 4 1 3

The first two times the seed value was 10, so we got the same output. The third time the value of the seed was 11, which generated a different output.

Generating random strings

Imagine that you want to generate random strings that can be used as difficult to guess passwords or for testing purposes. Based on random number generation, we create a utility that produces random strings. The utility is implemented as genPass.go and can be found in the ch02 directory of the book's GitHub repository. The core functionality of genPass.go is found in the next function.

func getString(len int64) string {
    temp := ""
    startChar := "!"
    var i int64 = 1
    for {
        myRand := random(MIN, MAX)
        newChar := string(startChar[0] + byte(myRand))
        temp = temp + newChar
        if i == len {
            break
        }
        i++
    }
    return temp
}

As we only want to get printable ASCII characters, we limit the range of pseudo-random numbers that can be generated. The total number of printable characters in the ASCII table is 94. This means that the range of the pseudo-random numbers that the program can generate should be from 0 to 94, without including 94. Therefore, the values of the MIN and MAX global variables, which are not shown here, are 0 and 94, respectively.

The startChar variable holds the first ASCII character that can be generated by the utility, which, in this case, is the exclamation mark, which has a decimal ASCII value of 33. Given that the program can generate pseudo-random numbers up to 94, the maximum ASCII value that can be generated is 93 + 33, which is equal to 126, which is the ASCII value of ~. All generated characters are kept in the temp variable, which is returned once the for loop exits. The string(startChar[0] + byte(myRand)) statement converts the random integers into characters in the desired range.

The genPass.go utility accepts a single parameter, which is the length of the generated password. If no parameter is given, genPass.go produces a password with 8 characters, which is the default value of the LENGTH variable.

Running genPass.go produces the following kind of output:

$ go run genPass.go
Using default values...
!QrNq@;R
$ go run genPass.go 20
sZL>{F~"hQqY>r_>TX?O

The first program execution uses the default value for the length of the generated string whereas the second program execution creates a random string with 20 characters.

Generating secure random numbers

If you intend to use these pseudo-random numbers for security-related work, it is important that you use the crypto/rand package, which implements a cryptographically secure pseudo-random number generator. You do not need to define a seed when using the crypto/rand package.

The following function that is part of the cryptoRand.go source code showcases how secure random numbers are generated with the functionality of crypto/rand.

func generateBytes(n int64) ([]byte, error) {
    b := make([]byte, n)
    _, err := rand.Read(b)
    if err != nil {
        return nil, err
    }
    return b, nil
}

The rand.Read() function randomly generates numbers that occupy the entire b byte slice. You need to decode that byte slice using base64.URLEncoding.EncodeToString(b) in order to get a valid string without any control or unprintable characters. This conversion takes place in the generatePass() function, which is not shown here.

Running cryptoRand.go creates the following kind of output:

$ go run cryptoRand.go   
Using default values!
Ce30g--D
$ go run cryptoRand.go 20
AEIePSYb13KwkDnO5Xk_

The output is not different from the one generated by genPass.go, it is just that the random numbers are generated more securely, which means that they can be used in applications where security is important.

Now that we know how to generate random numbers and random strings, we are going to revisit the phone book application and use these techniques to populate the phone book with random data.