This document provides an overview of the Go programming language. It discusses that Go was initially developed at Google in 2007 and is now an open source language used by many companies. The document then covers Why Go is useful, including its memory management, concurrency support, and cross-platform capabilities. It also summarizes some of Go's basic syntax like packages, functions, variables, types, and control structures. Finally, it discusses some key Go concepts like methods, interfaces, channels, and the net/http package.
Introduction
Go is initiallydeveloped at Google in 2007.
Go was announced in November 2009 and is used in some
of the Google’s production systems.
Go is an open source programming language.
Go 1 was released in March 2012
Currently, Go 1.8 released in 16 February 2017
Go is a general-purpose language.
Go is statically typed, compiled language.
4.
Why Go?
Go isan open-source but backed up by a large corporation.
Automatic memory management (garbage collection).
Strong focus on support for concurrency.
Fast compilation and execution
Statically type, but feels like dynamically typed
Good cross-platform support
Go compiles to native machine code
Rapid development and growing community
Used by big companies (Google, Dropbox, Docker, Cloudflare, Soundcloud)
5.
Important note
No typeinheritance
No method or operator overloading
No support for pointer arithmetic
No support for Assertions
No Exceptions - instead use an error return type
No Generics support
Too much Boilerplate (codes that have to be included in many places with little or no alteration)
Bad dependency management
Go uses URL based dependency imports
go get http://github.com/somename/somelibrary
import github.com/somename/somelibrary
6.
Basic commands
go isa tool for managing Go source code.
Usage:
go command [arguments]
The commands are:
build compile packages and dependencies
clean remove object files
doc show documentation for package or symbol
env print Go environment information
get download and install packages and dependencies
install compile and install packages and dependencies
run compile and run Go program
test test packages
version print Go version
Use "go help [command]" for more information about a command.
Go keywords
default
defer
else
fallthrough
for
Go hasonly 25 keywords, even less than English alphabet!
break
case
chan
const
continue
func
go
goto
if
import
interface
map
package
range
return
select
struct
switch
type
var
9.
Basic types
bool
string
int int8int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // alias for uint8
rune // alias for int32
float32 float64
complex64 complex128
10.
Packages
Every Go programis made up of package.
Program start running in package main.
Name is exported if it begins with a capital letter.
package main
import (
“fmt”
“math”
)
func main () {
fmt.Println(math.pi) //error
fmt.Println(math.Pi)
}
11.
Functions
// type comesafter the variable name
func add(x int, y int) int {
return x + y
}
// when arguments share the same type, type can be omitted but the last
func add(x, y int) int {
return x + y
}
func swap(x, y string) (string, string) {
return y, x // return multiple values
}
func hello(x, y string) (a, b string) {
a = x
b = y
return // name return value or naked return
}
12.
Variables
// variables withinitializers
var i, j int = 1, 2
var c, golang, java = false, true, “no!”
var c, golang, java bool
func main() {
var i int
}
Use var statement declare a list of variables.
Inside a functions, the := short assignment can be use in place of var
func main() {
c, golang, java := false, true, “no!”
}
13.
Zero values
var iint
var f float64
var b bool
var s string
fmt.Printf(“%v %v %v %qn”, i, f, b, s)
// output: 0 0 false “”
Variables declared without initial value are given their zero values.
0 for numeric types
false for boolean type
“” for string type
14.
Type conversion
// Goassignment between items of different type requires an explicit conversion
var i int = 42
var f float64 = float64(i)
var u unit = unit(f)
Constants
// Constants are declared like variables, but with the const keyword
const Pi = 3.14
15.
For
sum := 0
fori := 0; i < 10; i++ {
sum += i
}
// note: no () surrounding the three components; {} always required
Go has only one looping construct, the for loop.
For is Go’s while
sum := 1
for sum < 1000 {
sum += sum
}
16.
If else
if x:= math.Sqrt(100); x < 10 {
fmt.Printf(“Square root of 100 is %vn”, x)
} else {
fmt.Printf(“Square root of 100 is %vn”, x)
}
// note: no () surrounding the condition; {} always required
If can start with a short statement to execute before condition.
17.
Switch
package main
import (
"fmt”
"runtime”
)
funcmain() {
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println(" Go runs on OS X.”)
case "linux":
fmt.Println(" Go runs on Linux.”)
default:
fmt.Printf(" Go runs on %s.", os)
}
}
Switch can start with a short statement to execute before condition.
18.
Defer
func main() {
fmt.Println("countingdown”)
defer fmt.Print(”ndone”)
for i := 0; i < 10; i++ {
defer fmt.Print(i, “ ”)
}
}
// output:
counting down
9 8 7 6 5 4 3 2 1 0
done
Defers the execution of a function until the surrounding function returns
19.
Pointer
i := 21
p:= &i // store address of i in pointer variable p
fmt.Printf(“Address stored in p variable: %pn”, p) // print address
fmt.Printf(“Value of i is: %vn”, *p) // read i through the pointer
*p = 77 // set i through the pointer
fmt.Printf(“New value of i is: %vn”, i) // see the new value of i
Pointer is a variable whose value is the address of another variable.
Ampersand (&) operator denotes an address in memory.
Asterisk (*) operator denotes the pointer's underlying value.
Output:
Address stored in p variable: 0x1040e0f8
Value of i is: 21
New value of i is: 77
20.
Struct
type Vertex struct{
X int
Y int
}
func main() {
v := Vertex{1, 2}
p := &v
p.X = 1e9
fmt.Println(v)
}
// output: {1000000000 2}
Struct is a collection of fields
Struct fields are accessed using a dot
Struct fields can be accessed through a struct pointer
21.
Arrays & Slices
vara [10]int
Array has a fixed size.
Slice is a dynamically-size, flexible view of an array; var a []int
primes := [6]int{2, 3, 5, 7, 11, 13}
var s []int = primes[1:4]
fmt.Println(s)
// output: [3 5 7]
Slice is like reference to array; it does not store any data.
names := [4]string{“Jonh”, “Paul”, “George”, “Ringo”}
fmt.Println(names) // [John Paul George Ringo]
a := names[1:3]
fmt.Println(a) // [Paul George]
a[0] = "XXX”
fmt.Println(a) // [XXX George]
fmt.Println(names) // [John XXX George Ringo]
22.
Make function
func printSlice(sstring, x []int) {
fmt.Printf("%s len=%d cap=%d %vn", s, len(x), cap(x), x)
}
func main() {
a := make([]int, 5) // len(a) = 5; length of a is 5
printSlice("a", a) // output: a len=5 cap=5 [0 0 0 0 0]
b := make([]int, 0, 5) // len(b) = 0, cap(b) = 5
printSlice("b", b) // output: b len=0 cap=5 []
}
Slices can be created with the built-in make function; this is how you create
dynamically-sized array.
23.
Append function
Go providesa built-in append function
func main() {
var s []int
printSlice(s) // output: len=0 cap=0 []
s = append(s, 0) // append works on nil slices.
printSlice(s) // output: len=1 cap=2 [0]
s = append(s, 1) // The slice grows as needed.
printSlice(s) // output: len=2 cap=2 [0 1]
s = append(s, 2, 3, 4) // add more than one element at a time
printSlice(s) // output: len=5 cap=8 [0 1 2 3 4]
}
func printSlice(s []int) {
fmt.Printf("len=%d cap=%d %vn", len(s), cap(s), s)
}
24.
Range
Range form thefor loop iterates over a slice or map
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
for i, v := range pow {
fmt.Printf("2^%d = %dn", i, v)
}
// output:
2^0 = 1
2^1 = 2
2^2 = 4
2^3 = 8
2^4 = 16
2^5 = 32
2^6 = 64
2^7 = 128
25.
Map
make function returnsa map of the given type, initialized and ready to use
m := make(map[string]int) // initialized map
m["Answer"] = 42 // insert element
fmt.Println("The value:", m["Answer"]) // output: The value: 42
m["Answer"] = 48 // update element
fmt.Println("The value:", m["Answer"]) //output: The value: 48
delete(m, "Answer”) // delete element
fmt.Println("The value:", m["Answer"]) //output: The value: 0
v, ok := m["Answer”] // If key is in map, ok is true
fmt.Println("The value:", v, "Present?", ok) // If not, ok is false
// output: The value: 0 Present? false
26.
Function closures
Closure isa function value that references variable from outside its body
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos := adder()
for i := 0; i<5; i++ {
fmt.Print(pos(i), “ ”)
}
}
// output: 0 1 3 6 10
27.
Methods
A method isa function with a special receiver argument.
type MyFloat float64
func (f MyFloat) Abs() float64 {
if f < 0 {
return float64(-f)
}
return float64(f)
}
func main() {
f := MyFloat(-21)
fmt.Println(f.Abs())
}
// output: 21
Receiver type must be defined in the same package as the method.
28.
Pointer receivers
Methods withpointer receivers can modify the value to which the receiver points
type Vertex struct {
X, Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func main() {
v := Vertex{3, 4}
fmt.Println(v.Abs()) // output: 5
v.Scale(10)
fmt.Println(v.Abs()) // output: 50
}
29.
Interface
type I interface{
M()
}
type T struct {
S string
}
func (t T) M() { // This method means type T implements the interface I
fmt.Println(t.S)
}
func main() {
var i I = T{"hello”}
i.M() // output: hello
}
Interface type is defined as a set of method signatures.
A type implements an interface by implementing its methods.
There is no explicit declaration of intent, no "implements" keyword.
30.
Empty interface
func main(){
var i interface{}
describe(i) // output: (<nil>, <nil>)
i = 42
describe(i) // output: (42, int)
i = "hello"
describe(i) // output: (hello, string)
}
func describe(i interface{}) {
fmt.Printf("(%v, %T)n", i, i)
}
Interface type that specifies zero methods is known as the empty interface
An empty interface may hold values of any type.
Ex: fmt.Print takes any number of arguments of type interface{}
31.
Stringer
type Person struct{
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}
func main() {
a := Person{"Arthur Dent", 42}
fmt.Println(a) // output: Arthur Dent (42 years)
}
Stringer is defined by the fmt package
type Stringer interface {
String() string
}
Stringer is a type that can describe itself as a string
fmt package (and many others) look for this interface to print values
32.
Error
type MyError struct{
When time.Time
What string
}
func (e *MyError) Error() string {
return fmt.Sprintf("at %v, %s", e.When, e.What)
}
func run() error {
return &MyError{ time.Now(), "it didn't work” }
}
func main() {
if err := run(); err != nil {
fmt.Println(err) // at 2017-03-08 23:00:00 +0700 ICT, it didn't work
}
}
The error type is a built-in interface similar to fmt.Stringer
type error interface {
Error() string
}
33.
Reader
The io packagespecifies the io.Reader interface, which represents the read end
of a stream of data.
func main() {
r := strings.NewReader("Hello, Reader!”)
b := make([]byte, 8)
for {
n, err := r.Read(b)
if err == io.EOF {
break
}
fmt.Printf("n = %v err = %v b = %vn", n, err, b)
fmt.Printf("b[:n] = %qn", b[:n])
}
}
func (T) Read(b []byte) (n int, err error)
34.
Goroutine
Goroutines run inthe same address space, so access to shared memory must be
synchronized.
One goroutine usually uses 4 - 5 KB of stack memory.
Therefore, it's not hard to run thousands of goroutines on a single computer.
Goroutine is a lightweight thread managed by the Go runtime.
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world”)
say("hello")
}
// output:
world
hello
hello
world
world
hello
hello
world
world
hello
35.
Channel
Channel is oneof the features that make Golang unique.
The purpose of using Channel is to transfer values in goroutines.
ch <- v // Send v to channel ch.
v := <-ch // Receive from ch, and assign value to v.
Like maps and slices, channels must be created before use:
ch := make(chan int)
36.
Channel: example
Sum thenumbers in a slice, distributing the work between two goroutines.
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c) // [7 2 8]
go sum(s[len(s)/2:], c) // [-9 4 0]
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y) //output: -5 17 12
}
Once both goroutines completed their computation, it calculates the final result.
37.
Select
Select statement letsa goroutine wait on multiple communication operations.
A select blocks until one of its cases can run, then it executes that case. It
chooses one at random if multiple are ready.
func main() {
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
for {
select {
case <-tick:
fmt.Println("tick.")
case <-boom:
fmt.Println("BOOM!")
return
}
}
}
// output:
tick.
tick.
tick.
tick.
tick.
BOOM!
38.
net/http package
Package httpprovides HTTP client and server implementations.
More reader : https://golang.org/pkg/net/http/
func HandleFunc : registers the handler function for the given pattern in the DefaultServeMux.
Example : http.HandleFunc("/", hello)
func ListenAndServe : listens on the TCP network address and then calls Serve with handler to handle
requests on incoming connections. Accepted connections are configured to enable TCP keep-alives.
Example : http.ListenAndServe(":8080", nil)
package main
import (
"fmt"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello world!")
}
func main() {
http.HandleFunc("/", hello)
http.ListenAndServe(":8080", nil)
}
#5 Moreover, Go is “Simple”, readable; for example, you write go code, and a month later, you still understand it.
Go compiles to native machine code, so no need virtual machine installed in order to run go code.
#13 It’s similar to JavaScript but not like JavaScript; it will receive type when the first time initialize the value, so cannot assign other value in different type to the variable, it will cause compile error.
#14 Java cause warning, but golang assigns zero value.
#18 No break in golang switch; it will break by its own
#23 Make is a built in function, used to create dynamically-sized array, map, channel
#27 Each closure is bound to its own ’sum’ variable.
Global variables can be made local (private) with closures.
(Global) https://play.golang.org/p/ZQp7x8jBNZ
(Closures) https://play.golang.org/p/SIRhnEOmAA
Global variables live as long as your application (your window / your web page) lives.
Local variables have short lives. They are created when the function is invoked, and deleted when the function is finished.
#35 (Wait Group) https://play.golang.org/p/Pk-UAkRAoL
(Example) https://play.golang.org/p/6PHXHha_Uv
More than a dozen goroutines maybe only have 5 or 6 underlying threads.
#36 goroutines run in the same memory address space, so you have to maintain synchronization when you want to access shared memory.
How do you communicate between different goroutines?
Go uses a very good communication mechanism called channel
#37 By default, sends and receives block until the other side is ready.
This allows goroutines to synchronize without explicit locks or condition variables.
https://play.golang.org/p/7uavq8IgPm