Quick Golang 1

Posted on September 2, 2022
Tags: codeetc

1 Running or Building

go build main.go
./main
go run main.go

2 typical go file

package main
import (
	"fmt"
)
func main(){...}

3 Some surprises

for loops and if statements conditions do not have parenthesis.

3.1 := vs =

var bleh int = 3 equivalent bleh := 3

:= is shorthand to create new variable implicity then assign it.

//Shorthand
bleh := 2

//Expanded
var bleh int
bleh = 2

4 Use slice(list) instead of arrays

I will just call slice a list due to preference

Def list Array
init var x = []int{4,5,6}
var x = make([]int,3)
var x = [3]int{4,5,6}
comparison >= == Only with nil Yes
//ARRAY
var x = [6]int{1,3:4,7,5:9} //4 at pos 3, 9 at pos 5
  //[1,0,0,4,7,9]
var x2 = [...]int{6,4,3,3}
x == x2 //false

//SLICE
var z = make([]int,5) // [0,0,0,0,0]
var x = []int{1,2,3,4}
var y = [][]int
x == y //ERROR
y == nil //true

append returns a new array or slice.

4.1 Slicing lists

  • same as in Python BUT sublists SHARE THE SAME MEMORY
x = []int{1,2,3,4}
y = x[1:3]
y = []int{9,9}
//x is [1,9,9,4]

Never use Append with sublists

How to do the Pythonic subslice? Use copy
Warning if len doesn’t fit, it will NOT autoexpand the list; it will get cut off.

x = []int{1,2,3,4}
y = make([]int,2)
copy(y,x[1:3])

5 Strings

var s string = "Hello"
s[0] = "p" //ERROR - immutable

var e string = s[1:3] //Slice
e[0] = "p" //ERROR - immutable 
var b byte = s[2] // b = l
fmt.Printf("%s\n", string(b)) // output: l

var bb []byte = []byte(s[0:3])
fmt.Printf("%s\n", string(bb)) // output: Hel

6 loops

6.1 for loop

  for i:=0; i < 5; i++ {
	  sum += i
  }

6.2 iterator loops

  for keyX, ValX := range arr {
    fmt.Println(keyX)
    fmt.Println(ValX)
  }

6.3 object loops

arr := []Person{{"a",4}, {"b",5}, {"c",7}, {"d",4}, {"e",3}, {"f",1}}
for index, obj := range arr {
  fmt.Println(obj.Name)
  fmt.Println(obj.Age)
}

6.4 While loops

while (i != 5)

  var i int = 0
	for ; i != 5 ; {
		fmt.Println(i)
		i = i + 1
  }
	for i := 0; i != 5 ; {
		fmt.Println(i)
		i = i + 1
  }

7 Hashmap aka Dictionaries

var exMap1 map[string]int // value: nil

exMap2 := map[string][]int {
  "even": []int{0,2,4,6},
   "odd": []int{1,3,5,7},
}

val, ok := exMap2["none"] //ok = false, val = 0
val, ok := exMap2["even"]

exMap3 := make(map[string][]int,4)

8 Functions

func typicalfunction() string{
 return "simple function"
}

var mylambda = func() string { return "this is lambda string func" }
fmt.Println(mylambda())

8.1 Void function

  • Function that returns no values
// simple right?
func add(x int) {
	fmt.Println(x)
}

9 Struct and API

type person struct{
  name string
  age int
}

bob := person{
  name: "Joe",
  age: 2
}

9.1 Anonymous Struct

blob := struct {
  name string
  age int
}{
  name: "bob"
  age: 4
}

10 Scoping

func main(){
  x := 5
  if x > 0 {
      fmt.Println(x) //OUT: 5
      x := 3 
      fmt.Println(x) //OUT: 3 
  }
  fmt.Println(x) //OUT: 5
} 
go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest
go vet

11 Hashmap and loop assign

Both of these problems are similar to the problem of pass-by-value vs pass-by-reference.

11.1 modifying item list via loop

Below we are trying to modify the Size of the edges of a graph.

But since we can’t loop by-reference, we can use Indices.

BAD

 for index, edge := range mygraph.Edges{ //edge is just a COPY
 	edge.Size = 1 //this FAILS to modify the real thing
 }

GOOD

for i := range mygraph.Edges{ //use slice index to modify the real thing
 	mygraph.Edges[i].Attributes.Size = 1 //GOOD
}

11.2 modifying hashmap items

Below we are creating a hashmap from Node Keys : String to actual _ : Node struct

Similarly we can see that hashmap below is a map from string to a COPY of Node

BAD

nodeHashMap := make(map[string]Node) //string -> COPY of Node
 	for i := range mygraph.Nodes{
 		nodeHashMap[mygraph.Nodes[i].Key] = mygraph.Nodes[i] //FAIL to modify the real mygraph
 	}

GOOD

nodeHashMap := make(map[string]*Node) //string -> Pointer to Node
 	for i := range mygraph.Nodes{
 		nodeHashMap[mygraph.Nodes[i].Key] = &mygraph.Nodes[i] //GOOD
 	}

12 Learn by doing

gofunc Hello(name string) string {
  var bleh string
  var sentinel string
  arr := [3]int{1,2,3}
  const heh int = 3;
  var (
    target = 9
    curr = 3
  )
  const (
    pi = 3.14
    e = 2.718
  )
	if name == "bob" {
		sentinel = "pie"
	} else if name == "annie" {
		sentinel = "cola"
	}
	switch sentinel {
	case "bob":
		bleh = "bob likes pie"
		fmt.Println(bleh)
	}
  fmt.Println(arr[0])
  fmt.Println(heh)
	return "Hello World"
}

13 Switch statement

if i == 0 {
  fmt.Println("Zero")
}else if i == 1 {
  fmt.Println("One")
}else if i == 2{
  fmt.Println("Two")
}else {
  fmt.Println("default")
}
switch i {
  case 0: fmt.Println("Zero")
  case 1: fmt.Println("One")
  case 2: fmt.Println("Two")
  default: fmt.Println("default")
}

14 struct


type Rectangle struct {
    Width float64
    Height float64
}

func (r *Rectangle) AreaX int {
 return 5
}

func (r Rectangle) Area() int {
	return 5
}

func main(){
  rect := Rectangle{12, 6}
  outp := rect.Area()
  outpX := AreaX(&Rect)
  fmt.Println(outp)
  //5
}

Just by passing in the Rectangle argument for a method ‘Area()’, the method automatically is attached to struct ‘Rectangle’

15 Interfaces

How to implement an Interface:

In Golang, the act of calling ANY function that uses the interface is how the interface gets implemented implicity

interface IShape{
  float Area();
}
class Square implements IShape {
  float Length = 3;
  public float Area(){
    this.length * this.length
    };
}
public printArea(IShape s){
  System.out.println(s.Area());
}
Square x = new Square();
printArea(x)
type IShape interface {
  Area() float64
}
type Square struct {
  Length float64
}
func (s Square) Area() float64{ 
	return s.Length * s.Length
}
func printArea(s IShape){ //IShape defined as param in compiletime
  fmt.Println(s.Area())
}
x := Square{3}
printArea(x) //Square passed as param in runtime

Another example of interface

type PlayerStore interface{
	GetPlayerStore(name string) int
}
type PlayerServer struct{
	score PlayerStore
}
type StubPlayerStore struct {
	bleh map[string]int
}
func (s *StubPlayerStore) GetPlayerScore(name string) int {
	score := s.bleh[name]
	return score
}

16 Generics

//ofc dont use this since fmt.Println can do this already
func PrintList[T any]( x []T ) {
	for i,_ := range(x){
		fmt.Println(x[i])
	}	
	return
}

17 Pointer

Just as in our “Quick C” ,

func trans(ptr *int){
  *ptr = 0
}
func main(){
  x := 5
  trans(&x)

}

type range
int8 [-128,127]
int16 [-32768,32767]
int32 [-2147483648,2147483647]
int64 [–9223372036854775808,9223372036854775807]
uint8 [0,255]
uint16 [0,65536]
uint32 [0,4294967295]
uint64 [0,18446744073709551615]

Style

//BAD
name := "bob"
name := name + " ross"
//GOOD
const fstname = "bob"
const lstname = " ross"
const name = fstname + lstname
//BAD
arr := [3]int{7}
arr[1] = 8
arr[2] = 9
//GOOD
arr := [3]int{7}
arr2 := append(arr,[2]int{8,9})

17.1 Lambda

f := func() interface{}{return 2}
fmt.Println(f())
//output 2
fmt.Println((func() interface{}{return 2})())
//output 2

17.2 Tree

  • Golang does not allow recursive data structs, 2 ways to solve this:
    • Self-reference to self wrapped in a Functor
      • Tree self-refers to ListFunctor(Tree)
    • Use pointer to self
type tree struct{
    data int
    left []tree //tree wrapped in List functor
    right *tree //pointer to self
  }

   a := tree{data:2,left: []tree{tree{data:4}}}
   fmt.Println(a.left[0].data)
   b := tree{data:2,right: &tree{data:4}}
   fmt.Println(b.right.data)

18 Runes

//BAD
int main() {
    string str = "Hello, 世界!";

    int len = str.length();

    for(int i=0; i<len; i++){
        cout << i << " "; // Guess the output, now you can
    }

    cout << endl;

    for(int i=0; i<len; i++){
        cout << str[i] << " "; // Umm, you can sense that something unexpected will happen
    }
}
// OUTPUT:
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13
// H e l l o ,   � � � � � � !

//GOOD
int main() {
    string str = "Hello, 世界!";
    
    for(auto x = str.begin(); x != str.end(); x++) {
        cout << *x;
    }

    return 0;
}
// OUTPUT
// Hello, 世界!

typical loops will only loop byte by byte which cause errors when looping on non-standard characters like chinese runes.
Iterators will loop through runes.

Golang rune type is basically a better char

//BAD
func main() {
    str := "Hello, 世界!"

    for i:=0; i<len(str); i++ {
        fmt.Printf("%v", str[i]) // This will print the decimal values
    }

    for i:=0; i<len(str); i++ {
        fmt.Printf("%c", str[i]) // This will print the chars, but what happens to the chinese chars?
    }
}
// OUTPUT
// 72101108108111443222818415023114914033
// Hello, ä¸çŒ!

//GOOD
func main() {
    str := "世界"

    for i, v : range(str) {
        fmt.Println(i)
        fmt.Println(v)
    }
}

// OUTPUT
// 0
// 19990  <--This is 世 represented as 3 bytes unicode
// 3      <--3 bytes
// 30028  <--This is 界 represented as 3 bytes unicode

19 Scenarios

19.1 Loops and mutation fail

for index, edge := range mygraph.Edges{
	edge.Size = 1 //Fails to modify mygraph object
}

Why? edge.Size is just a local copy.

20 Traps

20.1 Pointer receivers and interfaces

  • server implements the ServeHTTP function to work
type MyServer struct {
}
func (p *MyServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	...
}
func main(){
  server := MyServer{} //FAILS to run server
	server := &MyServer{} //GOOD 
	http.ListenAndServe(":5000", server)
}
pointer receiver server Working?
func (p *MyServer) ServeHTTP server := MyServer{} FAILS
func (p *MyServer) ServeHTTP server := &MyServer{} WORKS
func (p MyServer) ServeHTTP server := MyServer{} WORKS
func (p MyServer) ServeHTTP server := &MyServer{} FAILS

Why?

  • The pointer receiver func (p *MyServer) ServeHTTP tells us ONLY A POINTER TO MyServer has the function ServeHTTP.
    • server := MyServer{} is NOT a POINTER to MyServer
    • server := &MyServer{} IS a POINTER to MyServer

21 JSON

reading a JSON request as AOB. We can print as a string

type Message struct {
	Data struct {
		Message     string `json:"message"`
		MessageType string `json:"messageType"`
	} `json:"data"`
	Datacontenttype string `json:"datacontenttype"`
  ...}

router.Handle("/something", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  bodyBytes, _ := io.ReadAll(r.Body)
  var msg Message;
  err := json.Unmarshal(bodyBytes,&msg)
  log.Println(string(bodyBytes)) //output string form of json
}))

JSON is []bytes in golang !!