Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

Overview

Installation

brew install go


Add it to your Path

Add the following to your .bashrc  or zshrc file

Code Block
export PATH="$PATH:$(go env GOPATH)/bin"


Configuration

Setup default workspace

...

go build

Install it

go install

Creating a Module

Create a go.mod file

Code Block
titlego.mod
module mymodule
go 1.18


Add Libraries

go get github.com/qopher/go-torrentapi


Commands

CommandDescription
go run <src.go>Run some code
go buildCompile the code. Outputs to local folder. Executable has folder as name.
go installCompiles and places the output in workspace/bin
go env GOPATHOutputs the default workspace folder

...

Code Block
package main

import (
  "fmt"
  "error"
  "math"
)

func main() {
  result, err := sqrt(16)
  
  if err != nil {
    fmt.Println(err)
  } else {
    fmt.Println(result)
  }
}

func sqrt(x float64) (float64, error ) {
  if x < 0 {
    return 0, errors.New("Undefined for negative numbers")
  }
  return math.Sqrt(x), nil
} 


Method Set

Code Block
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    ...
}

func (s *GracefulServer) BlockingClose() bool {
    ...
}

This is called the 'receiver'. In the first case (h handler) it is a value type, in the second (s *GracefulServer) it is a pointer. The way this works in Go may vary a bit from some other languages. The receiving type however, works more or less like a class in most object-oriented programming. It is the thing you call the method from, much like if I put some method A in side some class Person then I would need an instance of type Person in order to call A (assuming it's an instance method and not static!).

One gotcha here is that the receiver gets pushed onto the call stack like other arguments so if the receiver is a value type, like in the case of handler then you will be working on a copy of the thing you called the method from meaning something like h.Name = "Evan" would not persist after you return to the calling scope. For this reason anything that expects to change the state of the receiver, needs to use a pointer or return the modified value (gives more of an immutable type paradigm if you're looking for that).

Here's the relevant section from the spec; https://golang.org/ref/spec#Method_sets


Structs/Types

Example of Person Type

...

Go supports concurency by the use of the go command. All go functions in the background will terminate when the main terminates.

Code Block
package main
  
import (
  "fmt"
)

func main(){

  //run in background
  go count("sheep")

  go count("fish")

  //wait for keyboard press before exiting
  fmt.Scanln()

}

func count(thing string) {
  for i:=0; true; i++ {
    fmt.Println(i, thing)
    time.Sleep(time.Millisecond * 500)
  }
}


Using Channels

Channels are blocking

Code Block
package main

import (
  "fmt"
  "time"
)

func main(){

  //make channel of type string
  c := make(chan,string)	

  //run in background
  go count("sheep", c)

  //block until message is pushed to the channel
  msg:= <- c

  fmt.Println(msg)
}

func count(thing string, c chan string) {
  for i:=0; i <= 5; i++ {
    //send message on channel
    c <- thing
    time.Sleep(time.Millisecond * 500)
  }
} 

In the above code, the program exits once the count routine returns a message on the channel.


Code Block
package main

import (
  "fmt"
  "time"
)

func main(){

  //make channel of type string
  c := make(chan,string)	

  //run in background
  go count("sheep", c)

  //loop until count function closes the channel
  for {
    msg, open := <- c
    if !open {
      //channel closed, break out of for loop
      break
    }
  }

  fmt.Println(msg)
}

func count(thing string, c chan string) {
  for i:=0; i <= 5; i++ {
    //send message on channel
    c <- thing
    time.Sleep(time.Millisecond * 500)
  }

  //close channel
  close(c)
} 

Organizing your Code

Image Added

References