Summarize about basice usage of Go.

This post assumes that reader already know about other computer languages. This is not for computer language beginner.


Environment and Prerequisite

  • Go(1.15.8)
  • Experience with other programming languages


Installation

Mac

$ go version
go version go1.15.8 darwin/amd64

Ubuntu

  • Download file
curl https://golang.org/dl/go1.15.8.linux-amd64.tar.gz -o go1.15.8.linux-amd64.tar.gz
  • Install file
sudo tar -C /usr/local -xzf go1.15.8.linux-amd64.tar.gz
  • Add /usr/local/go/bin to PATH environment variable
  • It it fine to use like below but I recommend add to ~/.bash_profile or ~/.bashrc.
export PATH=$PATH:/usr/local/go/bin


Build and Test

  • Skip project directory structure because this only for basic language usage.

Write Basic Code

test.go

package main

import "fmt"

func main() {
	fmt.Println("Hello, world!")
}

Build and Run

  • Run after build
$ go build test.go
$ ./test
Hello, world!
  • Also possible like below
$ go run test.go
Hello, world!


Usage

Basic Code Form

test.go

// package name
// every Go program is made up of packages
// programs start running in package main
package main

// import other packages
import "fmt"

// main function
// it is like "void main()" in C language
func main() {
	fmt.Println("Hello, world!")
}
Hello, world!


Variable Declaration

Characteristics

  • Declare var variable type(its form is different from others)
  • There is pointer.
  • It can be declared in various ways like below.
package main

import "fmt"

func main() {
	/*
	variable examples
	*/
	var i int
	i = 1

	var j = 2

	var a,b int
	a = 3
	b = 4

	x := 5

	fmt.Println(i, j, a, b, x)


	/*
	constant examples
	*/

	const c = 10
	const str = "string"

	// multiple constants
	const (
    	visa = "Visa"
    	master = "MasterCard"
    	amex = "American Express"
	)

	fmt.Println(c, str, visa, master, amex)


	/*
	pointer example
	*/

	var ptrVal int = 100
	var ptr *int = &ptrVal

	*ptr = 150

	fmt.Println(ptrVal, *ptr)
}
1 2 3 4 5
10 string Visa MasterCard American Express
150 150


Condition Statement - if

Characteristics

  • After if must be true or false not a number.
package main

import "fmt"

func main() {
    testVal := 10

    if testVal % 3 == 1 {
        fmt.Println("Remainder is 1")
    } else if testVal % 3 == 2 {
        fmt.Println("Remainder is 2")
    } else {
        fmt.Println("Remainder is 0")
    }
}
Remainder is 1


Condition Statement - switch

Characteristics

  • It breaks switch statement if one case statement is settled.
  • If use fallthrough, then it continues next case statement.
package main

import "fmt"

func main() {
	var name string
    var category = 2

    switch category {
    case 1:
        name = "Good"
    case 2:
        name = "Very Good"
    case 3, 4: // multiple value can be used in case
        name = "Super Nice"
    default:
        name = "Power"
    }
    fmt.Println(name)
}
Very Good


Iteration - for

Characteristics

  • There is no while statement and only for statement is exist. We can use for statement like while statement.
  • Also we can use continue and break like C language.
package main

import "fmt"

func main() {

	// basic form
	var sum int = 0

	for i := 1; i < 10; i++ {
		sum += i
	}
	fmt.Println(sum)


	// range usage with array
	names := []string {"김씨", "이씨", "박씨"}

	// index variable is index of array or slice
	for index, name := range names{
		fmt.Println(index, name)
	}


	// for statement with only condition
	sum = 0
	i := 0

	for i < 10 {
		sum += i
		i++
	}
	fmt.Println(sum)
}
45
0 김씨
1 이씨
2 박씨
45


Function

Characteristics

  • It can return multi values like python.
  • ‘Pass By Reference’ exists like C++.
package main

import "fmt"

func exampleFunc (msg string) {
	fmt.Println(msg)
}

func exampleFuncReturn (msg string) string{
	return msg
}

func exampleFuncReturnMultiple (first int, second int) (int, int){
	return first, second
}

func exampleFuncPassByReference (val *int){
	*val += 10
}

func main() {
	exampleFunc("exampleFunc test")

	fmt.Println(exampleFuncReturn("exampleFuncReturn test"))

	a,b := exampleFuncReturnMultiple(3, 4)
	fmt.Println(a, b)

	var testVal int = 100
	exampleFuncPassByReference(&testVal)
	fmt.Println(testVal)
}
exampleFunc test
exampleFuncReturn test
3 4
110


Anonymous Function

Characteristics

  • We can assign function to variable and also there anonymous function which does not have function name.
package main

import "fmt"

func main() {

    sum := func (values []int) int {
        res := 0
        for _, val := range values {
            res += val
        }
        return res
    }

    fmt.Println(sum([]int {1, 2, 3}))


    sum2 := func (values ... int) int {
        res := 0
        for _, val := range values {
            res += val
        }
        return res
    }

    fmt.Println(sum2(1, 2, 3))
}
6
6


Array

package main

import "fmt"

func printResult(values [3]int) {

    for _, val := range values{
        fmt.Println(val)
    }
    fmt.Println()
}

func main() {

    var arr1 [3]int
    arr1[0] = 1
    arr1[1] = 2
    // arr1[2] will be 0 it is default value

    var arr2 = [3] int {1, 2, 3}
    var arr3 = [...] int {1, 2, 3}

    printResult(arr1)
    printResult(arr2)
    printResult(arr3)
}
1
2
0

1
2
3

1
2
3

Slice

Characteristics

  • It is dynamic size array. It supports append, merge, copy and sub-slice.
package main

import "fmt"

func main() {

    var sliceExample []int   
    sliceExample = []int{1, 1, 1}
    // also same as below
    // sliceExample := make([]int, 3, 1)


    // append
    sliceExample = append(sliceExample, 2)
    sliceExample = append(sliceExample, 3, 4, 5)
    fmt.Println(sliceExample)
    fmt.Println()


    // append slices
    sliceExampleA := []int{1, 2, 3}
    sliceExampleB := []int{4, 5, 6}
    fmt.Println(append(sliceExampleA, sliceExampleB...))
    fmt.Println()


    // sub-slice
    sliceExample  = []int{1, 2, 3, 4, 5}
    fmt.Println(sliceExample[:]) // 1 2 3 4 5
    fmt.Println(sliceExample[2:]) // 3 4 5
    fmt.Println(sliceExample[:4]) // 1 2 3 4
    fmt.Println(sliceExample[2:4]) // 3 4
}
[1 1 1 2 3 4 5]

[1 2 3 4 5 6]

[1 2 3 4 5]
[3 4 5]
[1 2 3 4]
[3 4]


Map

Characteristics

  • There is no order in map iteration.
package main

import (
    "fmt"
    "strconv"
)

func main() {

    var exampleMap map[string]int
    exampleMap = make(map[string]int)

    // add
    exampleMap["Mike"] = 100
    exampleMap["John"] = 110
    exampleMap["Jennie"] = 120

    // delete
    delete(exampleMap, "John")

    fmt.Println(exampleMap["Mike"])
    fmt.Println()

    // map iteration
    for key, value := range exampleMap {
        fmt.Println(key, value)
    }
    fmt.Println()

    // check key exist
    val, exist := exampleMap["Jennie"]
    if exist {
        fmt.Println("exist! its value is " + strconv.Itoa(val))
    }

}
100

Mike 100
Jennie 120

exist! its value is 120


Reference

파이썬(Python) 리스트(list)에서 중복된 원소를 제거하는 방법을 정리


환경

  • Python


중복된 원소들 제거

  • 딕셔너리(dictionary)에 키 값으로 넣었다가 다시 리스트로 변환한다.
  • 아래 방식으로 하면 리스트(list)에 집어 넣은 순서가 유지된다.
  • 버전마다 방식이 달라서 맞게 사용해야 한다. 관련된 내용들은 하단 참고자료에 첨부했다.


Python 2.7 이상

OrderedDict.fromkeys(iterable[, value])

  • 주어진 값들을 키 값으로 사용하는 딕셔너리(dictionary)를 반환한다. value가 있다면 모든 키 값들에 대해 value로 값이 정해지며 없다면 None이 된다.
  • OrderedDict: 파이썬 2.7부터 사용 가능
  • iterable에 추가된 원소들의 순서가 유지

예시

ex_list = [3, 4, 5, 6, 10, 1, 4, 5, 7, 8, 1, 5, 9]
from collections import OrderedDict
result = list(OrderedDict.fromkeys(ex_list))
print(result)
[3, 4, 5, 6, 10, 1, 7, 8, 9]

예시

ex_list = ['e', 'e', 'b', 'c', 'a', 'e', 'd', 'd', 'b', 'a']
from collections import OrderedDict
result = list(OrderedDict.fromkeys(ex_list))
print(result)
['e', 'b', 'c', 'a', 'd']


Python 3.7 이상

dict.fromkeys(iterable[, value])

  • 주어진 값들을 키 값으로 사용하는 딕셔너리(dictionary)를 반환한다. value가 있다면 모든 키 값들에 대해 value로 값이 정해지며 없다면 None이 된다.
  • 파이썬 3.7부터 iterable에 추가된 원소들의 순서가 유지
  • 3.6에서는 일부 구현은 지원하고 일부는 지원하지 않음

예시

ex_list = [3, 4, 5, 6, 10, 1, 4, 5, 7, 8, 1, 5, 9]
result = list(dict.fromkeys(ex_list))
print(result)
[3, 4, 5, 6, 10, 1, 7, 8, 9]

예시

ex_list = ['e', 'e', 'b', 'c', 'a', 'e', 'd', 'd', 'b', 'a']
result = list(dict.fromkeys(ex_list))
print(result)
['e', 'b', 'c', 'a', 'd']


참고자료

Post about removing duplicated elements in Python list


Environment and Prerequisite

  • Python


Remove Duplicated Elements

  • Insert to dictionary as key values and change those to list again.
  • By following below methods inserted order in list is preserved.
  • Different versions have different methods, so they should be used accordingly. Related things are in Reference.


Python 2.7 or higher

OrderedDict.fromkeys(iterable[, value])

  • Returns a dictionary using the given values ​​as key values. If there is a value, the value is set as value for all key values, otherwise it is None.
  • OrderedDict: Available starting with Python 2.7
  • Inserted elements order in iterable is preserved

Example

ex_list = [3, 4, 5, 6, 10, 1, 4, 5, 7, 8, 1, 5, 9]
from collections import OrderedDict
result = list(OrderedDict.fromkeys(ex_list))
print(result)
[3, 4, 5, 6, 10, 1, 7, 8, 9]

Example

ex_list = ['e', 'e', 'b', 'c', 'a', 'e', 'd', 'd', 'b', 'a']
from collections import OrderedDict
result = list(OrderedDict.fromkeys(ex_list))
print(result)
['e', 'b', 'c', 'a', 'd']


Python 3.7 or higher

dict.fromkeys(iterable[, value])

  • Returns a dictionary using the given values ​​as key values. If there is a value, the value is set as value for all key values, otherwise it is None.
  • Inserted elements order in iterable is preserved starting with Python 3.7
  • Partially supported in 3.6 implementation

Example

ex_list = [3, 4, 5, 6, 10, 1, 4, 5, 7, 8, 1, 5, 9]
result = list(dict.fromkeys(ex_list))
print(result)
[3, 4, 5, 6, 10, 1, 7, 8, 9]

Example

ex_list = ['e', 'e', 'b', 'c', 'a', 'e', 'd', 'd', 'b', 'a']
result = list(dict.fromkeys(ex_list))
print(result)
['e', 'b', 'c', 'a', 'd']


Reference

Dockerfile로 도커 이미지를 빌드할 때 다운로드할 파일이 변경되었어도 캐싱된 레이어를 사용해 변경된 파일이 적용되지 않는 경우에 대해서 정리


환경

  • Linux
  • Docker


문제 및 해결 방법

문제 상황

  • Dockerfile를 통해서 도커 이미지를 빌드할 때 RUN에서 curl을 이용해 파일을 다운로드 받는 부분이 있다. 이때, 새로운 이미지 빌드시 파일이 변경되었음에도 처음에 캐싱된 레이어의 파일이 들어가서 이전 파일이 이미지에 포함되는 문제가 발생한다.

문제 상황 예시

  • 파일 확인
$ curl https://twpower.me/test.txt
test1
  • Dockerfile 예시
$ cat Dockerfile
FROM ubuntu:18.04
RUN apt-get update -y
RUN apt-get install curl -y
RUN curl https://twpower.me/test.txt -o test.txt
CMD cat test.txt
  • 도커 이미지 빌드
$ sudo docker build --tag test:1.0 .
  • 빌드된 이미지 실행
$ sudo docker run test:1.0
test1
  • 변경된 파일 확인
$ curl https://twpower.me/test.txt
test2
  • 이미지 다른 버전으로 빌드
  • 하단에 캐시 이용하는거 확인
$ sudo docker build --tag test:2.0 .
Sending build context to Docker daemon  2.048kB
Step 1/5 : FROM ubuntu:18.04
 ---> 56def654ec22
Step 2/5 : RUN apt-get update -y
 ---> Using cache
 ---> 47696d4f4d5f
Step 3/5 : RUN apt-get install curl -y
 ---> Using cache
 ---> 15080e39cb8b
Step 4/5 : RUN curl https://twpower.me/test.txt -o test.txt
 ---> Using cache
 ---> 75bbac2b003f
Step 5/5 : CMD cat test.txt
 ---> Using cache
 ---> 3ce1a5c10a5b
Successfully built 3ce1a5c10a5b
Successfully tagged test:2.0
  • 빌드된 이미지 실행
  • 파일은 변경되었으나 변경된 파일이 적용되지 않은 문제 발생!
$ sudo docker run test:2.0
test1
$ curl https://twpower.me/test.txt
test2


원인

  • Dockerfile에서는 명령어 한줄 한줄을 레이어(Layer)로 판단하며 해당 레이어(Layer)별로 캐싱을 진행하기 때문에 만약 특정줄에 해당하는 명령어와 이전 명령어들이 동일하다면 동일한 레이어(Layer)로 판단하기 때문에 캐싱되어 있는 부분을 가져오기 때문이다.
  • 위의 예제에서는 파일이 변경되었어도 명령어 RUN curl https://twpower.me/test.txt -o test.txt는 동일하다.
  • 공식 홈페이지 문서 https://docs.docker.com/develop/develop-images/dockerfile_best-practices/에 따르면 “A Docker image consists of read-only layers each of which represents a Dockerfile instruction. The layers are stacked and each one is a delta of the changes from the previous layer.”라고 나와있다.


해결 방법

  • --no-cache를 이용해 도커 이미지 빌드시 캐시를 사용하지 않도록 설정
$ sudo docker build --no-cache --tag test:3.0 .


참고자료

Post about the case that changed file is not applied due to a cached layer even though the file to be downloaded is changed when building a docker image using Dockerfile


Environment and Prerequisite

  • Linux
  • Docker


Problem and Solution

Issue

  • When building a docker image through a Dockerfile, there is a part to download a file using curl in RUN. At this time, even though the file is changed when a new image is built, the file of the initially cached layer is included so the previous file is included in the image.

Issue Case Example

  • Check file
$ curl https://twpower.me/test.txt
test1
  • Dockerfile example
$ cat Dockerfile
FROM ubuntu:18.04
RUN apt-get update -y
RUN apt-get install curl -y
RUN curl https://twpower.me/test.txt -o test.txt
CMD cat test.txt
  • Build docker image
$ sudo docker build --tag test:1.0 .
  • Run the built image
$ sudo docker run test:1.0
test1
  • Check updated file
$ curl https://twpower.me/test.txt
test2
  • Build docker image with another version
  • Check that the cache is used in below
$ sudo docker build --tag test:2.0 .
Sending build context to Docker daemon  2.048kB
Step 1/5 : FROM ubuntu:18.04
 ---> 56def654ec22
Step 2/5 : RUN apt-get update -y
 ---> Using cache
 ---> 47696d4f4d5f
Step 3/5 : RUN apt-get install curl -y
 ---> Using cache
 ---> 15080e39cb8b
Step 4/5 : RUN curl https://twpower.me/test.txt -o test.txt
 ---> Using cache
 ---> 75bbac2b003f
Step 5/5 : CMD cat test.txt
 ---> Using cache
 ---> 3ce1a5c10a5b
Successfully built 3ce1a5c10a5b
Successfully tagged test:2.0
  • Run the built image
  • The file is changed but the changed file is not applied!
$ sudo docker run test:2.0
test1
$ curl https://twpower.me/test.txt
test2


Cause

  • In Dockerfile, each instruction line is considered as layer and cache is created per that layer. So if specific line and previous lines are same then, it is considered to be a same layer so it load layer from cache if it exists.
  • In above example, RUN curl https://twpower.me/test.txt -o test.txt is same but file is updated.
  • According to official document https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ it says “A Docker image consists of read-only layers each of which represents a Dockerfile instruction. The layers are stacked and each one is a delta of the changes from the previous layer.”.


Solution Methods

  • Use --no-cache to disable the cache using when building docker images
$ sudo docker build --no-cache --tag test:3.0 .


Reference