https://tour.golang.org/basics/11
// var card string = "Ace of Spades" // type can be inferred
card := "Ace of Spades" // := id for new variable initialisation
card = "Five of Diamonds" // var already exists and re-assigned
Each element must have the same type
- Array - fixed length
- Slice - grow or shrink
Slice
cards := []string{ "Ace of Diamonds", "Queen of Hearts"}
cards = append(cards, "Sizx of Spades") // new Slice is returned, original Slice is not modified
Accessing an element
cards[index]
Ranges
cards[0:2] // starting index : ending index => [inclusive:exclusive]
cards[:2] // same as the above
cards[2:] // all elements from indx 2 to the end
Using make
func
bs := make([]byte, 99999) // make func - creates a byte slice with 99999 empty elements
type deck []string
Usage
cards := deck{"Ace of Spades", "Queen of Hearts"}
Unused Variables
_
(similar to Elixir)
Data structure with fields
https://gobyexample.com/structs
- Pass by value (when arg into a func) - copy of struct is passed to a func. (see: notes on pointers)
Definition
(i) No attributes
type englishBot struct{}
func main() {
eb := englishBot{}
}
(ii) with attributes
type person struct {
firstName string
lastName string
}
Usage:
Ordering of fields matter
alex := person{"Alex", "Anderson"}
Being explicit
alex := person{firstName: "Alex", lastName: "Anderson"}
"Zero" values
var alex person // default "" for both attributes
fmt.Println(alex) // { }
fmt.Printf("%+v", alex) // {firstName: lastName:}
Assigning
alex.firstName = "Alex"
alex.lastName = "Anderson"
// {firstName:Alex lastName:Anderson}
Structs can be nested
type contactInfo struct {
email string
zipCode int
}
type person struct {
firstName string
lastName string
contact contactInfo
}
jim := person{
firstName: "Jim",
lastName: "Party",
contact: contactInfo{
email: "[email protected]",
zipCode: 94000,
},
}
Another way
type person struct {
firstName string
lastName string
contactInfo // dont need a var name
}
contactInfo: contactInfo{
email: "[email protected]",
zipCode: 94000,
},
- Pass by reference (when arg into a func)
colors := map[string]string{
"red": "#ff0000",
"green": "#4bf745",
}
Empty declaration
var colors map[string]string // map[]
colors := make(map[string]string)
Assigning
colors["white"] = "#ffffff"
Access
colors["white"]
Deleting
delete(colors, "white")
[]byte("Hi there!) // []type(value)
Go is a pass by value language i.e. receiver and args in a function is a copy
jim := person{ ... }
jimPointer := &jim
jimPointer.updateName("Jimmy")
func (pointerToPerson *person) updateName(newFirstName string) {
(*pointerToPerson).firstName = newFirstName
}
Definitions
&variable
- memory address of the variable*pointer
- value at the memory address
This still works (without &
)
jim.updateName("Jimmy")
jim.print()
func (pointerToPerson *person) updateName(newFirstName string) {
(*pointerToPerson).firstName = newFirstName
}
Gotcha:
Slice
is a pointer to the underlying Array. This is a reference
type
In the following func, the slice is a copy, but still points to the same underlying Array
e.g.
func main() {
mySlice := []string{"hi", "hello", "1", "2", "3"}
updateSlice(mySlice)
fmt.Println(mySlice)
}
func updateSlice(s []string) {
s[0] = "Bye"
}
Output: [Bye hello 1 2 3]
-> the original value was modified
- slices
- maps
- channels
- pointers
- functions
Hello world
package main
import "fmt"
func main() {
fmt.Println("Hi there!")
}
Run a file
go run main.go
go build # compiles
go run # compiles and run
go fmt # format
go install # compile and install package
go get # download source code from a package
go test # run tests
- executable - generates a runnable file e.g.
main.exe
(main is executable) - reusable - "helpers" that can be re-used e.g. package name would be specialised/specific (for a lib)
Example Structure:
main package
|_ main.go
|_ support.go
|_ helper.go
main.go
package main
func main() {
...
}
support.go
package main
func support() {
...
}
helper.go
package main
func help() {
...
}
func newCard() string {
return "Five of Diamonds"
}
type deck []string
func (d deck) print() {
for i, card := range d {
fmt.Println(i, card)
}
}
Usage
cards.print()
Receiver arg d
is usually one letter variable abbreviation of the type
Receiver - the "object" / "instance" being called on.
Can return more than one value
func deal(d deck, handSize int) (deck, deck) {
...
}
Usage:
hand, remainingCards := deal(cards, 5)
// equivalent to the below, as eb is not used
func (eb englishBot) getGreeting() string {
return "Hi There"
}
func (englishBot) getGreeting() string {
return "Hi There"
}
- Similar to a lambda or anon function
- unnamed function with code logic
// go literal (anon func) is a go routine
go func() {
// ...
}()
- Note: function literal (child routine) should not reference the same variable declared in the main routine
- Should pass the variable value -
pass by value
instead of reference
for l := range c {
// go literal (anon func) is a go routine
go func(link string) {
time.Sleep(5 * time.Second)
checkLink(link, c)
}(l)
}
for i, card := range cards {
fmt.Println(i, card)
}
When running go files when using a custom type defined in another file - must include the required files i.e.
go run main.go deck.go
if err != nil {
}
Implicit
type - i.e. don't need to specify that a struct type does not inherit from the Interface.
Definition
Note: the receiver type on getGreeting()
funcs
type bot interface {
getGreeting() string
}
type englishBot struct{}
type spanishBot struct{}
func (englishBot) getGreeting() string {
return "Hi There"
}
func (spanishBot) getGreeting() string {
return "Hola!"
}
Usage:
func main() {
eb := englishBot{}
sb := spanishBot{}
printGreeting(eb)
printGreeting(sb)
}
func printGreeting(b bot) {
fmt.Println(b.getGreeting())
}
Request
resp, err := http.Get("http://google.com")
Error Handling
if err != nil {
fmt.Println("Error:", err)
os.Exit(1)
}
(1) Reading response
bs := make([]byte, 99999) // make func - creates a byte slice with 99999 empty elements
resp.Body.Read(bs)
fmt.Println(string(bs))
(2) OR using os
package
io.Copy(os.Stdout, resp.Body) //arg 1: writer, arg2: reader
see: https://golang.org/pkg/io/#example_Copy
(3) Example using an interface
type logWriter struct{}
lw := logWriter{}
io.Copy(lw, resp.Body)
func (logWriter) Write(bs []byte) (int, error) {
fmt.Println(string(bs))
fmt.Println("Just wrote this many bytes:", len(bs))
return len(bs), nil
}
source := rand.NewSource(time.Now().UnixNano())
r := rand.New(source)
r.Intn(10) // generate numbers from 0 - 10
Filename: xxx_test.go
to test xxx.go
Run everything in the package: go test
Test names
func TestFuncName
Example
//t is the test handler
func TestNewDeck(t *testing.T) {
d := newDeck()
if len(d) != 16 {
t.Errorf("Expected deck length of 16 but got %d", len(d))
}
}
- lightweight thread of execution (child go routine)
- run async
- Go Scheduler runs one routine until it finishes or makes a blocking call (e.g. HTTP Request).
- Go by default uses one CPU core at a time
- Note: Concurrency is not parallelism - i.e. Go schedule mult threads but run one at a time (one core at a time)
Create it by calling go
then the function
go f(...)
Example: https://gobyexample.com/goroutines
- Used to communicate in between different Go routines
- Can send data into the channel from and to a Go routing
- Data shared between routines must be of the same type (string, float, structs etc). i.e. Channel that was created sharing string cannot have another type shared.
c := make(chan string) // make a channel, string data is passed in this channel
for _, link := range links {
go checkLink(link, c) // go routine is created and channel is passed to update
}
Note: the channel param c
is of type channel accepting string types
func checkLink(link string, c chan string) {
// ...
}
Send
c <- "Yep it's up"
Receive
- Waiting for messages from a channel is
blocking
fmt.Println(<- c)
Need to wait for all go routines
// infinite loop coninually checking link "l" in a channel "c"
// the link "l" is pushed into a channel and received from a channel
for l := range c {
go checkLink(l, c)
}
Definition
type MyError struct{}
func (m *MyError) Error() string {
return "boom"
}
Usage
func sayHello() (string, error) {
return "", &MyError{}
}
- Effective Go - https://golang.org/doc/effective_go.html (idiomatic Go)
- Packages - golang.org/pkg
- Proverbs - https://go-proverbs.github.io/
- Online REPL - https://play.golang.org/ (also repl.it)
- Receiver vs function arg - https://grisha.org/blog/2016/09/22/golang-receiver-vs-function/
- Testing https://blog.alexellis.io/golang-writing-unit-tests/
- Custom Errors https://www.digitalocean.com/community/tutorials/creating-custom-errors-in-go