Notes by Golang

Introduction

Article purpose is systematize my knowledge by Golang. Article is made as cases and their answer. This questions you can meet at an interview.

Questions

Why program work not correct and how fix it.

package main

import (
	"fmt"
)

type Person struct {
	FirstName string
	LastName  string
}

func (p Person) Married(husband Person) {
	p.LastName = husband.LastName
}

func main() {
	eva := Person{"Eva", "First"}
	adam := Person{"Adam", "Second"}
	eva.Married(adam)

	fmt.Println(eva)
}

In Golang you can pass function parameters by reference or by value. If parameter pass by value(as in our example), then it copies to new memory address and function works with this address and change value by it. If parameter pass by reference then it copies pointer for memory address, that was created and change value by this address.

For correct program working we must replace

func (p Person) Married(husband Person)

by

func (p *Person) Married(husband Person)

Now we pass function parameter by reference and example is working correct.

Why program work not correct and how fix it.

package main

import "fmt"

func main() {
	var actions []func()
	for _, dir := range [...]string{"one", "two", "three", "four"} {
		actions = append(actions, func() {
			fmt.Println(dir)
		})
	}

	for _, f := range actions {
		f()
	}
}

In example program creates deferred functions which will be reference by same memory address dir. Each loop iteration will rewrite this memory address, because now program print only last value.

For correct program working we must replace

actions = append(actions, func() {
	fmt.Println(dir)
})

by

a := dir
actions = append(actions, func() {
	fmt.Println(a)
})

Now each iteration will create new memory address with current value of dir.

Why program work not correct and how fix it.

package main

import (
	"fmt"
)
 
func showNumber(num int) {
	fmt.Println(num)
}

func main() {
	iterations := 10

	for i := 0; i <= iterations; i++ {
		go showNumber(i)
	}

	fmt.Println("Goodbye!")
}

The problem this code is gorutines don’t have time to work. When program is finish, gorutines are finish too.

Simple solution this is append time.Sleep for pause at the end. More correct variant is use package sync.WaitGroup.

Correct code is:

package main

import (
	"fmt"
	"sync"
)


 
func showNumber(num int) {
	fmt.Println(num)
}

func main() {
	var wg sync.WaitGroup
	iterations := 10

	for i := 0; i <= iterations; i++ {
		wg.Add(1)
		go showNumber(i)
	}
	
	wg.Wait()
	fmt.Println("Goodbye!")
}

In this code we create group which wait when all gorutines will done.

Why program doesn’t print “do is ok”:

package main

import (
	"fmt"
)

type MyError struct {
	Reason string
}

func (e *MyError) Error() string {
	return e.Reason
}

func do() error {
	var err *MyError
	fmt.Println(err == nil)
	return err
}

func main() {
	if err := do(); err == nil {
		fmt.Println("do is ok")
	}
}

Interface in Go include two elements type and value. Function do returns interface with type *MyError and value nil, i. e. (*MyError, nil). In Golang interface equals nil only when type and value equals nil, i. e. (nil, nil). In our examle we have (*MyError, nil) != (nil, nil).

  1. Pass by pointer vs pass by value in Go
  2. sync.WaitGroup
  3. Why is my nil error value not equal to nil
 
comments powered by Disqus