1.3. Hello Who?
Now that we have seen how to build the hello program we will look at its source code. Don’t worry about understanding all the details—everything shown in this chapter (and much more!) is covered thoroughly in the subsequent chapters. Here is the complete hello program (in file hello/hello.go):
Go uses C++-style comments: // for single-line comments that finish at the end of the line and /* ... */ for comments that can span multiple lines. It is conventional in Go to mostly use single-line comments, with spanning comments often used for commenting out chunks of code during development.4
Every piece of Go code exists inside a package, and every Go program must have a main package with a main() function which serves as the program’s entry point, that is, the function that is executed first. In fact, Go packages may also have init() functions that are executed before main(), as we will see (§1.7, → 40); full details are given later (§5.6.2, → 222). Notice that there is no conflict between the name of the package and the name of the function.
Go operates in terms of packages rather than files. This means that we can split a package across as many files as we like, and from Go’s point of view if they all have the same package declaration, they are all part of the same package and no different than if all their contents were in a single file. Naturally, we can also break our applications’ functionality into as many local packages as we like, to keep everything neatly modularized, something we will see in Chapter 9.
The import statement (14 ←, ➊) imports three packages from the standard library. The fmt package provides functions for formatting text and for reading formatted text (§3.5, → 93), the os package provides platform-independent operating-system variables and functions, and the strings package provides functions for manipulating strings (§3.6.1, → 106).
Go’s fundamental types support the usual operators (e.g., + for numeric addition and for string concatenation), and the Gostandard library supplements theseby providing packages of functions for working with the fundamental types, such as the stringspackage imported here. It is also possible to create our own custom types based on the fundamental types and to provide our own methods—that is, custom type-specific functions—for them. (We will get a taste of this in §1.5, → 21, with full coverage in Chapter 6.)
The reader may have noticed that the program has no semicolons, that the imports are not comma-separated, and that the if statement’s condition does not require parentheses. In Go, blocks, including function bodies and control structure bodies (e.g., for if statements and for for loops), are delimited using braces. Indentation is used purely to improve human readability. Technically, Go statements are separated by semicolons, but these are put in by the compiler, so we don’t have to use them ourselves unless we want to put multiple statements on the same line. No semicolons and fewer commas and parentheses give Go programs a lighter look and require less typing.
Go functions and methods are defined using the func keyword. The main package’s main() function always has the same signature—it takes no arguments and returns nothing. When main.main()finishes the program will terminate and return 0 to the operating system. Naturally, we can exit whenever we like and return our own choice of value, as we will see (§1.4, → 16).
The first statement in the main() function (14 , ➋; using the := operator) is called a short variable declaration in Go terminology. Such a statement both declares and initializes a variable at the same time. Furthermore, we don’t need to specify the variable’s type because Go can deduce that from the initializing value. So in this case we have declared a variable called who of type string, and thanks to Go’s strong typing we may only assign strings to who.
As with most languages the if statement tests a condition—in this case, how many strings were entered on the command-line—which if satisfied executes the corresponding brace-delimited block. We will see a more sophisticated if statement syntax later in this chapter (§1.6, → 29), and further on (§5.2.1, → 190).
The os.Args variable is a slice of strings (14 , ➌). Arrays, slices, and other collection data types are covered in Chapter 4 (§4.2, → 146). For now it is sufficient to know that a slice’s length can be determined using the built-in len() function and its elements can be accessed using the [] index operator using a subset of the Python syntax. In particular, slice[n] returns the slice’s nth element (counting from zero), and slice[n:] returns another slice which has the elements from the nth element to the last element. In the collections chapter we will see the full generality of Go’s syntax in this area. In the case of os.Args, the slice should always have at least one string (the program’s name), at index position 0. (All Go indexing is 0-based.)
If the user has entered one or more command line arguments the if condition is satisfied and we set the who string to contain all the arguments joined up as a single string (14 ←, ➍). In this case we use the assignment operator (=), since if we used the short variable declaration operator (:=) we would end up declaring and initializing a new who variable whose scope was limited to the if statement’s block. The strings.Join() function takes a slice of strings and a separator (which could be empty, i.e., ""), and returns a single string consisting of all the slice’s strings with the separator between each one. Here we have joined them using a single space between each.
Finally, in the last statement (14←, →), we print Hello, a space, the string held in the who variable, and a newline. The fmt package has many different print variants, some like fmt.Println() which will neatly print whatever they are given, and others like fmt.Printf() that use placeholders to provide very fine control over formatting. The print functions are covered in Chapter 3 (§3.5, → 93).
The hello program presented here has shown far more of the language’s features than such programs conventionally do. The subsequent examples continue in this vein, covering more advanced features while keeping the examples as short as possible. The idea here is to simply acquire some basic familiarity with the language and to get to grips with building, running, and experimenting with simple Go programs, while at the same time getting a flavor of Go’s powerful and novel features. And, of course, everything presented in this chapter is explained in detail in the subsequent chapters.