Golang Learning

Json unmarshaling

Structs and json tags

Something i always forget is that not only the `json:“field”` thing is not necessary but the key names have to be uppercased:

type User struct {
  Id       int    `json:"id"`
  Name     string `json:"name"`
  Email    string `json:"email"`
  Username string `json:"username"`
  Address  struct {
    Street string `json:"street"`
    City   string `json:"city"`
  } `json:"address"`
}

Otherwise things don’t un marshal properly , also nice you can nest structs like that

Main idea about having a data struct defined before unmarshaling

I struggled to come to terms with this idea , but if you are consuming a large json object from any give endpoint you are likely to know the format or what values are you after. The values that are not declared in the type you are unmarshaling into ,simple don’t unmarshal

for example if you have this json:

{
  "name": "Jerry",
  "age": : 40,
  "email": "garciaj.uk@gmail.com"
}

and you unrmarshal into:

type User struct {
  Name string `json:"name"`
}

That will only unmarshal the name and discard everything else … in a way kind of a nice thing.

Channels Select and GoRoutines

Basics

So you know channels are a way for goroutines to receive and send data and they have a type eg , This is declaring a channel of type int and after we declare an anonymous function that we tell it should take a chan int as an argv and at the end of the function we pass out the channel itself

out := make(chan int)
go func(c chan int) {
  defer close(c)
  c <- 1
  time.Sleep(1 * time.Second)
  c <- 2
  time.Sleep(1 * time.Second)
  c <- 3
  time.Sleep(1 * time.Second)
  c <- 4
  time.Sleep(1 * time.Second)
}(out)

You can see how doing simply

c <- 1

is enough to send data into the channel , now if you want to get data out of the channel is somewhat similar

fmt.Println(<-c)

or something like

mymsg := <-c

Also channels return two arguments when reading from them , the second argument is a bool that says if the channel is still open , and therefor you should still be reading from it:

msg, open := <-out:

open is the bool that tells you if the channel is still open

What happens if you have multiple channels?

The more goroutines you might run the more channels you need to create, there’s a function called select which can take a bunch of channels and read from whatever channel is ready first:

select {
case msg, open := <-out:
    fmt.Printf("Message from out: %d\n", msg)
case msg1, open1 := <-out1:
    fmt.Printf("Message from out1: %d\n", msg1)
    }

The good thing about select , is that it actually reads from whatever channel is ready first , is not sequential or blocking.

Scoped variables

declaring variable inside ifs or others

package main

import "fmt"

func main() {
    a := 1
    fmt.Println(a)
    {
        a := 2
        fmt.Println(a)
    }
    fmt.Println(a)
}

prints 1 2 1

you need to

func main() {
    a := 1
    fmt.Println(a)
    {
        a = 2
        fmt.Println(a)
    }
    fmt.Println(a)
}

and that should print 1 2 2

Pass by value pass by reference

This would explain everything you need to know about pointers

Pass by value, you just passing the value and not the memory location , so in short it copies the value into a function Negatives of that depend on how large the value is

Pass by reference , passes a pointer to the real variable so when you change it inside a function it does change the value of the real variable

  fmt.Println("Pass by value")
myint := 10
fmt.Println(myint)
// pass by value ->
func(m int) {
  m++
  fmt.Println(m)
}(myint)

fmt.Println(myint)
/*This prints
  10
  11
  10
*/

// pass by referece ->
fmt.Println(myint)
func(m *int) {
  *m = 100
  fmt.Println(*m)
}(&myint)
fmt.Println(myint)
/*This prints
10
100
100
*/

Pointers

It’s important to note also that the json unmarshal function takes pointers to the variable you just declared (see &posts)

var posts []User
...
body, err := ioutil.ReadAll(resp.Body)
...
json.Unmarshal(body, &posts)
for u := range posts {
  fmt.Printf("User: %s\n", posts[u].Name)
  fmt.Printf("Address.Street: %s\n", posts[u].Address.Street)
  fmt.Printf("Address.City: %s\n", posts[u].Address.City)
}

Buffers and Readers

IO Readers

func main() {
  conn, err := net.Dial("tcp", "google.com:80")
  if err != nil {
    fmt.Println(err)
    os.Exit(1)
  }
  fmt.Fprint(conn, "GET HTTP 1.0\r\n\r\n")
  buf := make([]byte, 20)
  if err != nil {
    panic(err)

  }
  for {
    n, err := conn.Read(buf)
    if err == io.EOF {
      break
    }
    if n > 0 {
      fmt.Println(string(buf[:n]))
    }

  }

}

Custom IO Writer

So an interface is whatever struct that implements a given method , i don’t really get this 100% but

If there’s a struct called dog that has a function called Walk , and there is an interface that says something like :

type Animals interface {
  Walk(b []byte) (n int, err error)
}

Then the struct called Dog implements the interface called Animal , maybe it is like classes but quite implicit, as you don’t have to write: Dog implements Animal kind of thing like in java

So i declare an interface called my MyWriter , that has a signature method (function) called Write, Then i define a struct that without knowing will be part of the interface , because it implements a Write function

And because of that i can print to it.

the go definition of fmt.Fprint is:

func Fprint(w io.Writer, a ...interface{}) (n int, err error)

So it needs an io.Writer , io.Writer look like:

type Writer interface {
  Write(p []byte) (n int, err error)
}

So what i get is that as long pass a struct to fmt.Fprint that implements ANY interface that has a Write function , then its ok

So this is my code:

type MyWriter interface {
  Write(b []byte) (n int, err error)
}

type MyRealWriter struct {
}

func (rr MyRealWriter) Write(b []byte)(n int , err error) {
  fmt.Printf("%T -> %d\n",b , len(b))
  fmt.Println(string(b))
  return 10,nil
}

func main() {
  var ddd MyRealWriter
  fmt.Fprint(ddd, "jeronimo")
}

And it works!

Go Templates

A very tiny example

So templating is good to generate files and placeholders, for example

type Me struct {
  Name        string
  Lastname    string
}

func main() {
  td := Me{"Jeronimo","Garcia"}

  t, err := template.New("todos").Parse("Hi {{ if eq .Name \"Jeronimo\" }} {{ .Lastname }} {{ else }} Anonymous {{ end }} \n")
  if err != nil {
    panic(err)
  }
  err = t.Execute(os.Stdout, td)
  if err != nil {
    panic(err)
  }
}

You can see Template.New takes a random name todos , but the Parse method takes a string where the values will be interpolated

Executing the templates

Now on the Execute step we pass where we want this to be rendered os.Stdout and the struct we want to use to interpolate with:

err = t.Execute(os.Stdout, td)
if err != nil {
  panic(err)
}

FuncMap

You can make your own functions and map them into the template engine so they can be used inside the template eg:

      t, err := template.New("todos").Funcs(template.FuncMap{"isitme":func(person string) bool {
  if person == "Jeronimo" {
    return true
  }
  return false
}}).Parse("Hi {{ if eq .Name \"Jeronimo\" }} {{ .Lastname }} {{ else }} Anonymous {{ end }} {{ if isitme .Name }} It's ME! {{else}} not me!{{end}}\n")

pretty simple , the output is

 jgarcia at x1 in ~/Projects/si/golang/templates
$ go run main.go
Hi  Garcia   It's ME!

Mux and net/http and socket

Writing binary data in sockets

func main() {
  conn, err := net.Dial("tcp", "127.0.0.1:5672")
  if err != nil {
    fmt.Println(err)
    os.Exit(1)
  }
  b := make([]byte,8)
  binary.LittleEndian.PutUint16(b[0:], 0x0008)
  binary.LittleEndian.PutUint16(b[1:6], 0x0000)
  binary.LittleEndian.PutUint16(b[6:], 0xce00)
  binary.Write(conn,binary.LittleEndian,b)
  if err != nil {
    panic(err)

  }
}

Packages

Interfaces

How to check if a type implements an interface

type Cars interface {
  Run(wheels int) (runs bool)
}

type Twingo struct {
}
type Xr struct {
}

func (t Twingo) Run(w int) (runs bool) {
  if w == 4 {
    return true
  }
  return false
}

func main() {
  var t Twingo
  fmt.Println(t.Run(4))
  // This is to check if a type implements an interface
  var _ Cars= (*Twingo)(nil)
  var _ Cars= (*Xr)(nil)
}

Which returns

 $ go run main.go
# command-line-arguments
./main.go:27:6: cannot use (*Xr)(nil) (type *Xr) as type Cars in assignment:
        *Xr does not implement Cars (missing Run method)

Casting variables and types

So this is mainly to cast empty interfaces to types for example

func main() {
  var m interface{} = 1
  mm := m.(int)
  fmt.Println(strconv.Itoa(mm))
}

So you basically assign any value to an empty interface and then you cast it to .(string) for example

This is a more complicated example where i try to move from “{ “name”: [1,2,3] } to a proper data type:

func main() {
  var caca interface{}
  myjson := `{"name": [11,22,33] }`
  json.Unmarshal([]byte(myjson), &caca)
  mcaca, ok := caca.(map[string]interface{})
  if !ok {
    panic(ok)
  }
  cc := mcaca["name"]
  fmt.Println(reflect.TypeOf(cc))
  for i,d := range cc.([]interface{}){
    fmt.Println(i)
    fmt.Println(reflect.TypeOf(d))
  }
}

the tricky bit is actually casting the “[11,22,33]” as a “[]interface{}” , as the key part happens on:

for i,d := range cc.([]interface{}){

So the key is already casted as a string

Generics

Is a way to pass generic types to a function , as long as the fulfill the interface ,

For example without generics if you wanted to implement a Join() function you would need to define one for int one for stirngs and so fort.

Generics kind of fix this

type Auto interface {
      Run() bool

}
type Car struct {
}

func (c Car) Run() bool{
  return true
  }

func Runs[T Auto](things []T) (result []bool) {
    for _, v := range things {
        result = append(result,v.Run())
    }
    return result
}
func main() {
  var xr Car
  var twingo Car
  fmt.Print(Runs([]Car{twingo,xr}))

}