There are three main ways to get user input: firstly, by reading the command-line arguments of a program; secondly, by asking the user for input; or thirdly, by reading external files. This section will present the first two ways. Should you wish to learn how to read an external file, you should visit Chapter 8, Telling a UNIX System What to Do.
Getting user input
About := and =
Before continuing, it will be very useful to talk about the use of := and how it differs from =. The official name for := is the short assignment statement. The short assignment statement can be used in place of a var declaration with an implicit type.
The := operator works as follows:
m := 123
The result of the preceding statement is a new integer variable named m with a value of 123.
However, if you try to use := on an already declared variable, the compilation will fail with the following error message, which makes perfect sense:
$ go run test.go # command-line-arguments ./test.go:5:4: no new variables on left side of :=
So, you might now ask, what will happen if you are expecting two or more values from a function and you want to use an existing variable for one of them. Should you use := or =? The answer is simple: you should use :=, as in the following code example:
i, k := 3, 4 j, k := 1, 2
As the j variable is used for the first time in the second statement, you use := even though k has already been defined in the first statement.
Although it may seem boring to talk about such insignificant things, knowing them will save you from various types of errors in the long run!
Reading from standard input
The reading of data from the standard input will be illustrated in stdIN.go, which you will see in two parts. The first part is as follows:
package main import ( "bufio" "fmt" "os" )
In the preceding code, you can see the use of the bufio package for the first time in this book.
Although the bufio package is mostly used for file input and output, you will keep seeing the os package all the time in this book because it contains many handy functions; its most common functionality is that it provides a way to access the command-line arguments of a Go program (os.Args).
The official description of the os package tells us that it offers functions that perform OS operations. This includes functions for creating, deleting, and renaming files and directories, as well as functions for learning the UNIX permissions and other characteristics of files and directories. The main advantage of the os package is that it is platform independent. Put simply, its functions will work on both UNIX and Microsoft Windows machines.
The second part of stdIN.go contains the following Go code:
func main() {
var f *os.File f = os.Stdin defer f.Close() scanner := bufio.NewScanner(f) for scanner.Scan() { fmt.Println(">", scanner.Text()) } }
First, there is a call to bufio.NewScanner() using standard input (os.Stdin) as its parameter. This call returns a bufio.Scanner variable, which is used with the Scan() function for reading from os.Stdin line by line. Each line that is read is printed on the screen before getting the next one. Please note that each line that is printed by the program begins with the > character.
The execution of stdIN.go will produce the following kind of output:
$ go run stdIN.go This is number 21 > This is number 21 This is Mihalis > This is Mihalis Hello Go! > Hello Go! Press Control + D on a new line to end this program! > Press Control + D on a new line to end this program!
According to the UNIX way, you can tell a program to stop reading data from standard input by pressing Ctrl + D.
Working with command-line arguments
The technique of this section will be illustrated using the Go code of cla.go, which will be presented in three parts. The program will find the minimum and the maximum of its command-line arguments.
The first part of the program is as follows:
package main import ( "fmt" "os" "strconv" )
What is important here is realizing that getting the command-line arguments requires the use of the os package. Additionally, you need another package, named strconv, in order to be able to convert a command-line argument, which is given as a string, into an arithmetical data type.
The second part of the program is the following:
func main() { if len(os.Args) == 1 { fmt.Println("Please give one or more floats.") os.Exit(1) } arguments := os.Args min, _ := strconv.ParseFloat(arguments[1], 64) max, _ := strconv.ParseFloat(arguments[1], 64)
Here, cla.go checks whether you have any command-line arguments by checking the length of os.Args. This is because the program needs at least one command-line argument to operate. Please note that os.Args is a Go slice with string values. The first element in the slice is the name of the executable program. Therefore, in order to initialize the min and max variables, you will need to use the second element of the string type os.Args slice that has an index value of 1.
There is an important point here: the fact that you are expecting one or more floats does not necessarily mean that the user will give you valid floats, either by accident or on purpose. However, as we have not talked about error handling in Go so far, cla.go assumes that all command-line arguments are in the right format and therefore will be acceptable. As a result, cla.go ignores the error value returned by the strconv.ParseFloat() function using the following statement:
n, _ := strconv.ParseFloat(arguments[i], 64)
The preceding statement tells Go that you only want to get the first value returned by strconv.ParseFloat() and that you are not interested in the second value, which in this case is an error variable, by assigning it to the underscore character. The underscore character, which is called blank identifier, is the Go way of discarding a value. If a Go function returns multiple values, you can use the blank identifier multiple times.
The third part comes with the following Go code:
for i := 2; i < len(arguments); i++ { n, _ := strconv.ParseFloat(arguments[i], 64) if n < min { min = n } if n > max { max = n } } fmt.Println("Min:", min) fmt.Println("Max:", max) }
Here, you use a for loop that will help you to visit all the elements of the os.Args slice, which was previously assigned to the arguments variable.
Executing cla.go will create the following kind of output:
$ go run cla.go -10 0 1 Min: -10 Max: 1 $ go run cla.go -10 Min: -10 Max: -10
As you might expect, the program does not behave well when it receives erroneous input; the worst thing of all is that it does not generate any warnings to inform the user that there was an error (or several) while processing the command-line arguments of the program:
$ go run cla.go a b c 10 Min: 0 Max: 10