
Go is an open-source, compiled, concurrent, imperative, structured, garbage-collected, system-programming language.
Also known as golang.
The reason I started learning Go is simple; the syntax.
The python-like syntax is very easy to adapt to, and just might be the best feature of this gem of a language, besides being very fast due to its compiled nature.
Isn't it developer utopia?
A language with python like syntax and C like performance!
Other major reasons include my inquisitiveness and a search engine company called Google, which develops and supports the language; also it is open-source!
Development of Go commenced in September of 2007 at Google lead by Robert Griesemer, Rob Pike, and Ken Thompson.
Go became a public open source project on November 10, 2009. After a couple of years of very active design and development, stability was called for and Go 1 was released on March 28, 2012. Go 1, which includes a language specification, standard libraries, and custom tools, provides a stable foundation for creating reliable products, projects, and publications.
From Go FAQ
What is the purpose of the project?
No major systems language has emerged in over a decade, but over that time the computing landscape has changed tremendously. There are several trends:
Computers are enormously quicker but software development is not faster.
Dependency management is a big part of software development today but the “header files†of languages in the C tradition are antithetical to clean dependency analysis—and fast compilation.
There is a growing rebellion against cumbersome type systems like those of Java and C++, pushing people towards dynamically typed languages such as Python and JavaScript.
Some fundamental concepts such as garbage collection and parallel computation are not well supported by popular systems languages.
The emergence of multicore computers has generated worry and confusion. We believe it's worth trying again with a new language, a concurrent, garbage-collected language with fast compilation. Regarding the points above: It is possible to compile a large Go program in a few seconds on a single computer.
Go provides a model for software construction that makes dependency analysis easy and avoids much of the overhead of C-style include files and libraries.
Go's type system has no hierarchy, so no time is spent defining the relationships between types. Also, although Go has static types the language attempts to make types feel lighter weight than in typical OO languages.
Go is fully garbage-collected and provides fundamental support for concurrent execution and communication.
By its design, Go proposes an approach for the construction of system software on multicore machines.
package main
import "fmt"
func main () {
fmt.Println("Hello, World!")
}
The command line front-end for Go is go, file names end with a .go extension. The
go build file-namecommand produces an executable binary.
Go insists on having your code organized in a specific manner. The GOPATH environment variable in your operating system should specify your workspace, from the Go doc:
Workspaces
The go tool is designed to work with open source code maintained in public repositories. Although you don't need to publish your code, the model for how the environment is set up works the same whether you do or not.
Go code must be kept inside a workspace. A workspace is a directory hierarchy with three directories at its root:
- src contains Go source files organized into packages (one package per directory),
- pkg contains package objects, and
- bin contains executable commands.
The go tool builds source packages and installs the resulting binaries to the pkg and bin directories.
The src subdirectory typically contains multiple version control repositories (such as for Git or Mercurial) that track the development of one or more source packages.
The user works in the src subdirectory in a module's folder. Where the module is a program file that you create.
The go command can be used as follows.
syntax: go <command> <arguments>
Here arguments refer to Go source code files, commonly used commands:
The first statement in a Go source file must be the package name where name is the package's default name for imports. (All files in a package must use the same name.)
Go's convention is that the package name is the last element of the import path: the package imported as "crypto/rot13" should be named rot13.
Executable commands must always use package main.
There is no requirement that package names be unique across all packages linked into a single binary, only that the import paths (their full file names) be unique.
The following line demonstrates a Go import.
syntax: import "<package name>"
Multiple imports are possible by using tuple-like declarations.
syntax: import ("<package-1 name>" "<package-2 name>")
fmt package is the stdio.h equivalent. Print and Println functions are present like in Java. Printf is also present which provides the much required formatted output programming.
Some important packages: fmt, net, os, time, math
Using Println from fmt.
syntax: fmt.Println(<arg>)
After importing a package, one can refer to the names it exports. In Go, a name is exported if it begins with a capital letter.
Variables are declared differently as compared to other traditional languages. The var keyword declares a variable followed by the name followed by the type.
syntax: var <name> type //normal variable
syntax: var <name> [size]type //array variable
Variables are intialized with default values; for integers and floats 0 and 0.0 respectively and 'false' for booleans.
Declarations can include initializers one per variable. If initial value is present the type can be omitted.
syntax: var x, y, z int = 1, 2, 3
syntax: var c, python, java = true, false, "no!" //java is string type
Short declaration can be used inside functions with := omitting the 'var' keyword.
//code
package main
import "fmt"
func main() {
var x, y, z int = 1, 2, 3
c, python, java := true, false, "no!"
fmt.Println(x, y, z, c, python, java)
}
Variables can be declared as constants by replacing 'var' with the 'const' keyword. High precision constant numeric values take their type through context.
if-else in Go is similar to the general if-else construct of other languages, though there are some minor differences.
- Condition enclosing parenthesis are optional.
- break, continue, return, goto required for if without else.
//code
package main
import "fmt"
func main() {
var a,b int = 1,2
if a>b {
fmt.Println("a is bigger.")
} else {
fmt.Println("b is bigger.")
}
}
Similar to for-loop if can have a pre-condition to execute before checking the condition.
//code
package main
import (
"fmt"
"math"
)
func pow(x, n, lim float64) float64 {
if v := math.Pow(x, n); v < lim {
return v
}
return lim
}
func main() {
fmt.Println(
pow(3, 2, 10),
pow(3, 3, 20),
)
}
Variables declared inside a short if statement are also accessible by the else block.
The switch statement provides an alternative to the if-else-if ladder.
//code
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Print("Go runs on ")
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
// freebsd, openbsd,
// plan9, windows...
fmt.Printf("%s.", os)
}
}
Like all other constructs the switch-case construct also supports a pre-condition to execute before performing the comparisons. Case body breaks automatically unless it ends with a fallthrough statement.
In Go, switch-case works with data-types such as a string. In contrast to languages like C which provide switch-case only for primitive types such as ints and char.
A switch with no condition behaves as switch true, essentially a cleaner way to represent an if-else-if ladder.
//code
package main
import (
"fmt"
"time"
)
func main() {
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("Good morning!")
case t.Hour() < 17:
fmt.Println("Good afternoon.")
default:
fmt.Println("Good evening.")
}
}
Go has only one looping construct the for loop.
//code
package main
import "fmt"
func main() {
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
fmt.Println(sum)
}
As in Java, you can leave the initial and final steps empty, similarly, in Go you can drop the extraneous semi-colons and the construct then behaves as a while loop.
//code
package main
import "fmt"
func main () {
i:= 0
for i<10 {
fmt.Println (i+1)
}
}
Go has support for pointers.
syntax: var <name> *<type> = &<variable>
syntax: var <name> *<type> = new <type>
syntax: <name> := new <type>
Go is memory safe hence, pointer arithmetic is not permitted.
Values associated with pointers can be accessed with the * operator.
//code
package main
import "fmt"
func main() {
p := 5
q := &p
fmt.Println("p =", p)
fmt.Println("q =", q)
fmt.Println("p =", *q)
}
Arrays in Go are directly influenced by lists in Python; the following behaves exactly as it behaves in Python.
//code
package main
import "fmt"
func main() {
p := []int{2, 3, 5, 7, 11, 13}
fmt.Println("p ==", p)
fmt.Println("p[1:4] ==", p[1:4])
fmt.Println("p[:3] ==", p[:3])
fmt.Println("p[4:] ==", p[4:])
}
For those who do not know Python.
syntax: p := []int {1,2,3} //initializes an array
syntax: p[start:end]
The above means a slice of the array that starts from the start index and goes upto end-1 index inclusive.
In simpler words slice begins at start position and contains end-start elements.
syntax: p[:end] // is same as p[0:end]
The above syntax refers to a slice with all the elements from the 0 index, till it has end elements.
syntax: p[start:] // is same as p[start:len(p)]
This syntax slices from and including the start index to the end of the array.
Slices can also be created with the make function
syntax: make ([]type, <length>, <capacity>)
The capacity parameter is optional and if not provided, defaults to the given value of length.
An array's length can be accessed through the len() function and its maximum capacity can be obtained by using the cap() function.
Note: In Go nil is equivalent to None/null/NULL of other languages, signifying nothing.
Go also provides advanced for loops like Python.
//code
package main
import "fmt"
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
}
Alternative advanced for loops include the following:
//code
package main
import "fmt"
func main() {
pow := make([]int, 10)
for i := range pow {
pow[i] = 1 << uint(i)
}
for _, value := range pow {
fmt.Printf("%d\n", value)
}
}
Functions are declared with func keyword. The function prototype is different than other traditional languages.
//code
package main
import "fmt"
func add(x int, y int) int {
return x + y
}
func main() {
fmt.Println(add(42, 13))
}
Prototype is func <name> (arg <type>) <return type>
Functions can take zero or more inputs. If multiple inputs are of the same type then the type specifier can be omitted from all but the last argument.
syntax: function (x int, y int) int //this can be rewritten as
syntax: function (x, y int) int //also correct
Like Python functions can also return multiple values.
//code
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}
The return parameter in the prototype can be declared in the prototype, hence value/s can be returned with just the return statement.
//code
package main
import "fmt"
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}
func main() {
fmt.Println(split(17))
}
Note: Functions are values too and hence can be assigned to variables.
Go has support for structures. The following demonstrates a struct for storing coordinates:
//code
package main
import "fmt"
type Vertex struct {
X int
Y int
}
func main() {
fmt.Println(Vertex{1, 2})
}
Note: the type keyword is the Go equivalent of C's typedef. Structs can be assigned to variables in the following manners:
syntax: var <name> <struct-name>
syntax: <name>:= <struct-name>{}
syntax: <name>:= new(struct-name>)
syntax: var (
p = Vertex{1, 2} // has type Vertex
q = &Vertex{1, 2} // has type *Vertex
r = Vertex{X: 1} // Y:0 is implicit
s = Vertex{} // X:0 and Y:0
)
The variables can be accessed by using the . operator. Structs can also be accessed through pointers. Though unlike the -> operator, pointers also use the . operator to access sub-fields.
Go has an in-built map type that implements a hash-map where each entry is a key-value pair similar to that of a dictionary in Python.
//code
package main
import "fmt"
var m map[string]int
func main() {
m = make(map[string]int)
m["Author"] = 151294
fmt.Println(m["Author"])
}
Maps are made with make keyword (not new)
Map literals demonstration:
//code
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m = map[string]Vertex{
"Bell Labs": Vertex{
40.68433, -74.39967,
},
"Google": Vertex{
37.42202, -122.08408,
},
}
func main() {
fmt.Println(m)
}
If the top-level is a type name (as the above example) it can be removed.
syntax: var m = map[string]Vertex{
"Bell Labs": {40.68433, -74.39967},
"Google": {37.42202, -122.08408},
}
Basic map operations:
m[key] = elemelem = m[key]delete(m, key)elem, ok = m[key]If key is in m, ok is true. If not, ok is false and elem is the zero value for the map's element type.