Why Go?¶
Go is an application-oriented programming language developed by programmers at Google. One of the major use cases for Go is writing servers, and so much of the language is written to support this.
Much of what follows is based on the Go FAQ. This is a good starting place for learning about the design of Go.
Some of the major features of Go are:
Fast compilation. Go is designed from the ground up for writing large, multi-file programs. In languages like C and C++, compiling and linking multi-file programs is surprisingly time-consuming due in large part to the use of
#define
to combine files. Many large C++ programs can’t be efficiently built on a single computer, and so sophisticated distributed build systems are used to make build times more reasonable.Apparently, the designers of Go got the idea for creating it during a 45 minute wait for a C++ compilation.
Lightweight typing. Go is a statically typed language, like C++ or Java. Yet this is done in such a way that it feels closer in spirit to non- statically typed languages, like Python or JavaScript. You can often avoid explicitly dealing with types.
Novel use of interfaces. Go is object-oriented, but it does not have classes or inheritance (at least in the sense of C++ or Java). Instead, interfaces and methods are combined to provide most of the same benefits of traditional object-oriented programming.
Garbage collection. As in Java or Python, there’s no need to explicitly de-allocate memory. This simplifies code, and goes a long way towards stopping memory leaks and preventing dangling pointers.
Closures. Go supports anonymous functions (i.e. lambda functions), which are functions without names. Anonymous functions are allowed to refer to variables outside of themselves, and so you can pass and return functions.
Concurrency support. Go uses channels and so-called “go routines” (essentially lightweight processes) to handle most concurrency tasks. These are based on a model of concurrency known as communication sequential processes.
No exceptions. The designers of Go believe that exception systems in languages like C++ and Java ultimately lead to convoluted code that treats too many situations as errors (e.g. they believe that a failure to open a file should not be treated as an exception). Instead, Go relies on explicit error codes returned from functions, along with the functions
defer
,panic
, andrecover
.Pretty good standard tools and library. Out of the box, Go comes with useful tools for things like source code formatting (
go fmt
) and testing (go test
). It also has an extensive standard library with many practical packages. For instance, it is relatively easy to create a simple web-server in Go using just its standard library.
Hello, Go!¶
Here is the basic “Hello, world!” program in Go:
// hello.go
//
// To run this, type the following at the command-line:
//
// $ go run hello.go
//
package main
import "fmt"
func main() {
fmt.Println("Hello from Go!")
}
A few thing to notice:
- Go code is organized into packages, and a runnable Go program must have
one package called
main
, and within that, it must have one function calledmain
. fmt
is a package in the Go standard library that contains basic reading and writing functions such asfmt.Println
.- Code statements can end with a
;
, but don’t need to. In practice, they are rarely used to end statement. - All function declarations start with
func
. - Source code comments work as in C/C++, i.e.
//
to the end of a line is a comment, and everything/*
and*/
is a comment. - Go is a compiled language, and we will be mainly using the
go run
command to compile and run our programs in one step. Go usually compiles pretty quickly, and so using go run` can make it feel quite interactive. - The command
go fmt
can be used to format a Go program in a standard way, which greatly increases code readability. Many Go editors will automatically callgo fmt
every time you save your code so that it will stay in a nearly formatted style all the time.
Prime Number Sample Code¶
Here is the prime number checking code used in some of the lectures:
// primes.go
package main
import (
"fmt"
)
func isPrime(n int) bool {
if n < 2 {
return false
} else if n == 2 {
return true
} else if n%2 == 0 {
return false
} else { // n > 2
trialDiv := 3
for trialDiv*trialDiv <= n {
if n%trialDiv == 0 {
return false
}
trialDiv += 2
} // for
return true
} // if
}
func isPrime2(n int) bool {
switch {
case n < 2:
return false
case n == 2:
return true
case n%2 == 0:
return false
default: // n > 2
trialDiv := 3
for trialDiv*trialDiv <= n {
if n%trialDiv == 0 {
return false
}
trialDiv += 2
} // for
return true
} // switch
}
// table-driven testing
var prime = []int{2, 3, 5, 7, 11, 13, 17, 31, 37, 101}
var notPrime = []int{-2, -1, 0, 1, 4, 6, 8, 9, 10, 12, 91, 100}
func testIsPrime(isPrime func(int) bool) {
for _, n := range prime {
if !isPrime(n) {
fmt.Printf("testIsPrime: %v is prime!\n", n)
panic("error!")
}
}
for _, n := range notPrime {
if isPrime(n) {
fmt.Printf("testIsPrime: %v is not prime!\n", n)
panic("error!")
}
}
fmt.Println("all testIsPrime tests passed")
}
func countPrimesLessThan(n int) (count int) {
if n < 2 {
return 0
} else {
for i := 2; i < n; i++ {
if isPrime(i) {
count++
}
}
return count
}
}
func main() {
testIsPrime(isPrime)
testIsPrime(isPrime2)
// nvals := []int{10, 100, 1000, 10000, 100000}
// for _, n := range nvals {
// fmt.Printf("countPrimesLessThan(%v)=%v\n", n, countPrimesLessThan(n))
// }
// for i := 0; i < len(nvals); i++ {
// fmt.Printf("countPrimesLessThan(%v)=%v\n", nvals[i], countPrimesLessThan(nvals[i]))
// }
// for i := 0; i <= 25; i++ {
// fmt.Printf("isPrime2(%v) = %v\n", i, isPrime2(i))
// }
} // main
Notes on Go¶
Here are some notes introducing various basic features of Go:
- Variables
- Control Structures: if statements, switch, and loops
- Functions
- Pointers
- Structures
- Slices and Arrays
- Maps
- Methods, Interfaces, and an Example of Sorting
- Concurrency: Introduction to Goroutines and Channels
- Example programs:
- hello1.go
- hello2.go
- loop1.go
- loop2.go
- slice1.go
- slice2.go (slice notation)
- slice3.go (slices refer to an underlying array)
- slice4.go (using
make
) - numstats1.go (includes simple file reading, and functions)
- numstats2.go (includes simple file reading, and functions)
- a Go version of cat -n (read/write files, errors,
defer
) - a simple scanner (includes
map
,iota
,switch
) - types1.go (new type with
type
) - types2.go (structs, methods)
- types3.go (the empty interface
interface{}
, type switch, type assertion) - types4.go (example of an interface)
- functions1.go (example of passing a function as a value; also shows table-driven testing)
- functions2.go (a function that returns a function: asking a question)
- functions3.go (a function that returns a function: numerical derivative)
- functions4.go (the map function in Go, and why it doesn’t work well)
- functions5.go (example of returning and using a closure)