czehik / go-lang-cheat-sheet

Useful cheat sheet for Go programming language(syntax, features, examples and more)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

#Go Cheat Sheet

Useful cheat sheet for Go programming language(syntax, features, examples and more).

##Credits Most of the examples taken from A Tour of Go, The Golang spec and Google I/O talks.

##Table of contents:

##Structs Defining and accessing structs:

type Man struct {
	name	string
	age		int
}

func main() {

	man1 := Man{"Ariel", 26}
	man2 := Man {
		age: 24,
		name: "Ben",
	}
	var man3 Man
	man3.name = "Dan"
	man3.age = 25

	//accessing structs
	for _, man := range []Man {man1, man2, man3} {
			println(man.name)
	}
}

Methods for structs:

func (man Man) sayHello() {
	println("Hello buddy, my name is: ", man.name)
}

func main() {
	ariel := Man{ "Ariel", 26 }
	ariel.sayHello()
}

#Arrays Defining and accessing arrays:

func main() {
	//declare
	var arr [1]string
	//set
	arr[0] = "Hello World!"
	//read
	println(arr[0]) //Hello World!
	
	//declare and initialize
	arr1 := [2]int{1, 2}
	//the compiler count capacity for you
	arr2 := [...]int{3, 4} 
}

#Slices Defining and accessing slices:

func main() {
	str := []string {"Hello"}

	println(str[0]) // Hello
}

Increase capacity of slice:

func main() {
	str := []string {"Hello"}
	str = append(str, "World!")

	println(str[0], str[1]) //Hello World!
}

Slicing slices:
Slices can be re-sliced, creating a new slice value that points to the same array.
Usage: slice[low:high]

import "fmt"

func main() {
	arr := []int{2,4,6,8,10,12,14}
	
	fmt.Println(arr[1:4]) // slice from index 1 to 3, Result: [4 6 8]
	fmt.Println(arr[:4]) // missing low index implies 0, Result: [2 4 6 8]
	fmt.Println(arr[4:]) // missing high index implies len(a), Result: [10 12 14]
}

Making slices:
Usage: make(T, n) or make(T, n, m)

func printSlice(x []int) {
	fmt.Printf("%v, length=%d, capacity=%d\n",
		x, len(x), cap(x))
}

func main() {

	a := make([]int, 5)
	printSlice(a) //[0 0 0 0 0], length=5, capacity=5

	b := make([]int, 0, 5)
	printSlice(b) //[], length=0, capacity=5

	//We reslice the slice to add 5 to its original length
	//We can do this because cap(slice) == 5
	b = b[:cap(b)]
	for i := 0; i < cap(b); i++ {
		b[i] = i
	}
	printSlice(b) //[0 1 2 3 4], length=5, capacity=5

	c := b[:2]
	printSlice(c) //[0 1], length=2, capacity=5

	d := c[2:5]
	printSlice(d) //[2 3 4], length=3, capacity=3

}

#For statements
Go has only one looping construct, the for loop. (the { } are required!)

func main() {
	for i := 0; i < 10; i++ {
		println(i)
	}
	
	//You can leave the pre and post statements empty.
	sum := 1
	for ; sum < 1000; {
		sum += sum
	}
	fmt.Println(sum)
}

While statement:
for is Go's while

func main() {
	sum := 1
	for sum < 1000 {
		sum += sum
	}
	fmt.Println(sum)
}

Forever:

func main() {
    for {
    }
}

#Functions Declaration:

func printTwice(str string) {
	println(str, str)
}

func main() {
	printTwice("foo")
}

Returing value:

func add(x int, y int) int {
	return x + y
}

func main() {
	println(add(10, 20))
}

Returing multiple values:

import "strings"

func trim(str string, word string) (res string, i int){
	//splits the string
	fields := strings.Fields(str)

	for _, e := range fields {
		if(e == word) {
			i++
			continue
		}
		res += e + " "
	}
	return res, i
}

func main() {
	//calling a function that return multiple values
	newStr, len:= trim("foo bar baz foo", "foo")
	println("trimmed string:", newStr)
	println("times of showing:", len)
}

#Range The range form of the for loop iterates over a slice or map.

func main() {
	var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
	
    	for i, v := range pow {
		fmt.Printf("2**%d = %d\n", i, v)
    	}
    
    	//if you only want the index, drop the "v" entirely.
    	for i := range pow {
        	fmt.Printf(i)
    	}
    
    	//or, you can skip the index or value by assigning to _
    	for _, value := range pow {
        	fmt.Printf("%d\n", value)
    	}
}

#Maps Maps must be created with make (not new) before use

func main() {
	foo := make(map[string]int)
	foo["a"] = 1
	foo["b"] = 2
	foo["c"] = 3

	println(foo["a"], foo["b"], foo["c"]) //1 2 3
}

Map literals:
Map literals are like struct literals, but the keys are required

type Human struct {
	name 	string;
	gender 	string;
	age	 	int;
}

func main() {
	group := map[int8]Human {
		0: Human {
			"Ariel M.", "Man", 26,
		},
		//you can omit the type from the element literal
		1: {
			"Dan J.", "Man", 45,
		},
	}

	fmt.Println(group[0], group[1]) //{Ariel M. Man 26} {Dan J. Man 45}
}

#Go Builtin
new: The expression new(T) allocates a zeroed T value and returns a pointer to it.

type Human struct {
	name 	string;
	gender 	string;
	age	 	int;
}

func main() {
	me := new(Human)
	fmt.Println(*me)//{  0}

	me.name, me.gender, me.age = "Ariel", "Male", 26
	fmt.Println(*me)//{Ariel Male 26}
}

#Goroutines What is goroutine?
It's an independently executing function, lunched by go statement.
It has it's own call stack, which grows and shrinks as required.
It's very cheap, It's practical to have thousands, even hundreds of thousands of goroutines.

It's not thread.
There might be only one thread in a program with thousands goroutines.

Instead, goroutines are multiplexed dynamically onto threads as needed to keep all goroutines running.
But if you think of it as a very cheap thread, you won't be far off.
Credits: Rob Pike presentation

import(
    t "time"
    f "fmt"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        t.Sleep(100 * t.Millisecond)
        f.Println(s)
    }
}

func main() {
    go say("world")
    say("hello")
}

#Channels A channel in Go provides a connection between two goroutines, allowing them to communicate.
By default, sends and receives block until the other side is ready.

//Declaring and initializing
var c1 chan int
c1 = make(chan int)
//or
c2 := make(chan int)
	
//Sending on a channel
c1 <- 1
c2 <- 2
	
//Receiving from a channel
//The arrow(<-) indicates the direction of data flow
res1, res2 := <-ch, <-ch

Example:

func seq(num int, c chan int) {
	x, y := 0, 1
	for num != 0 {
		x, y = y, x + y
		num--
	}
	c <-x
}

func main() {
	//channels must be created before use
	ch := make(chan int)
	go seq(50, ch)
	go seq(20, ch)

	res1, res2 := <-ch, <-ch
	println(res1, res2) //12586269025 6765
}

Rob Pike example:

// When the main function executes <-c, it will wait for a value to be sent.
// Similarly, when the boring function executes c <- value, it waits for a receiver to be ready.
// A sender and receiver must both be ready to play their part in the communication. 
// Otherwise we wait until they are.
// Thus channels both communicate and synchronize.

func boring(msg string, c chan string) {
	for i := 0; ; i++ {
		c <- fmt.Sprintf("%s %d", msg, i) //Expression to be sent can be any suitable value.
		time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
	}
}

func main() {
	c := make(chan string)
	go boring("boring!", c)

	for i:= 0; i < 5; i++ {
		fmt.Printf("You say: %q\n", <-c) //Receive expression is just a value
	}
	fmt.Println("You're boring! I'm leaving...")
}

Generator: Generator: function that returns a channel.
Channels are first-class values, just like strings and integers.

func boring(msg string) <-chan string { // Returns receive-only channel of strings.
	c := make(chan string)
	go func() { // We launch the goroutine from inside the function
		for i := 0; ; i++ {
			c <- fmt.Sprintf("%s %d", msg, i) //Expression to be sent can be any suitable value.
			time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
		}
	}()
	return c // Return the channel to the caller
}

func main() {
	joe, ann := boring("Joe"), boring("Ann")
	for i:= 0; i < 5; i++ {
		fmt.Printf("Joe say: %q\n", <-joe)
		fmt.Printf("Ann say: %q\n", <-ann)
	}
	fmt.Println("You're both boring; I'm leaving...")
}

Multiplexing: These programs make Joe and Ann count in lockstep.
We can instead use a fan-in function to let whosoever is ready talk.

func fanIn(input1, input2 <-chan string) <-chan string {
	c := make(chan string)
	go func () { for { c <- <-input1 } }()
	go func () { for { c <- <-input2 } }()
	return c
}

func main() {
	// We actually decoupled the execution
	c := fanIn(boring("Joe"), boring("Ann"))
	for i:= 0; i < 20; i++ {
		fmt.Println(<-c)
	}
	fmt.Println("You're both boring; I'm leaving...")
}

Lets Rewrite our fanIn function using select, (only one goroutine is needed).
see: Select statement

func fanIn(input1, input2 <-chan string) <-chan string {
	c := make(chan string)
	go func() {
		for {
			select {
			case s := <-input1: c <- s
			case s := <-input2: c <- s
			}
		}
	}()
	return c
}

range and close:
A sender can close a channel to indicate that no more values will be sent.
Receivers can test whether a channel has been closed by assigning a second parameter to the receive expression.
Usage:

// ok will be false if there are no more values to receive 
// and the channel is closed.
v, ok := <-ch
func fibonacci(n int, c chan int) {
    x, y := 0, 1
    for i := 0; i < n; i++ {
        c <- x
        x, y = y, x+y
    }
    close(c)
}

func main() {
    c := make(chan int, 10)
    go fibonacci(cap(c), c)
    //the loop receives values from the channel repeatedly until it is closed.
    for i := range c {
        fmt.Println(i)
    }
}

Note:

  • Only the sender should close a channel.
  • You don't usually need to close the channels. closing is only necessary when the receiver must be told there are no more values coming, e.g: range loop.

#Buffered Channels Go channels can be also be created with a buffer.
Buffering removes synchronization.
Buffering makes them more like Erlang's mailboxes.

Buffered channels can be important for some problems, but they are more subtle to reason about.
Sends to a buffered channel block only when the buffer is full. Receives block when the buffer is empty.
Usage: ch := make(chan int, length)

func main() {
    c := make(chan int, 2)
    c <- 1
    c <- 2
    fmt.Println(<-c)
    fmt.Println(<-c)
}

#Select A control structure unique to concurrency.
The reason channels and goriutines are built in into the language.

The select statement provides another way to handle multiple channels.
It's like a switch statement, but each case is a communication.

  • All channels are evaluated.
  • Selection blocks until one communication can proceed, which then does.
  • If multiple can proceed, select choose pseudo-randomly.
  • A default clause, if present, executes immediately if no channel is ready.
func main() {
	c1, c2, c3 := boring("foo"), boring("bar"), boring("baz")
	time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond) // Add timeout
	select {
	case v1 := <-c1:
		fmt.Printf("Received %v from c1\n", v1)
	case v2 := <-c2:
		fmt.Printf("Received %v from c2\n", v2)
	case v3 := <-c3:
		fmt.Printf("Received %v from c3\n", v3)
	default:
		fmt.Printf("No one was ready to communicate\n")
	}
}
ezoic increase your site revenue

About

Useful cheat sheet for Go programming language(syntax, features, examples and more)