10. if
• [Python]
if x > 0:
• [Go]
if x > 0 {
}
• initialization statement
if ok := check(); ok {
11. for
• [Python]
for value in value_list:
• [Go]
• for i, value := range array { // array, slice, map 순회
• for init; condition; post { // c style
for i := 0; i < 10; i++ {
• for condition { // while 문 처럼 사용
• for { // 무한 루프
18. 함수 선언
• [Python]
• def sum(x, y):
return x + y
• [Go]
• func sum(x, y int) int {
return x + y
}
• 매개변수, 리턴값 모두 type 명시 필요!
• func sum(x, y int) (int, err) { 와 같이 여러개의 리턴값도 리턴 가능!
19. 이쯤에서 생기는 궁금증...
• int 말고 다른 type을 더하고 싶으면 어떻게 해야 할까... ???
• method overloading을 하면 되려나???
• func sum(x, y int) int {
return x + y
}
func sum(x, y float64) float64 {
return x + y
}
• compile error .. - “sum redeclared in this block”
21. interface{}
• interface는 method의 집합 (단, 메서드 자체를 구현하
지는 않음.)
• method가 정의되지 않은 빈 인터페이스(interface{})는
어떠한 조건도 없기 때문에 모든 type의 값 대입이 가능.
• func sum (x, y interface{})
22. type switch
• switch x.(type) {
case int:
…
case float64:
…
• interface는 내부적으로 실제 값의 type에 관한 정보들을 저장
하고 있는 itable 에 대한 pointer를 가지고 있음.
• type switch를 사용하면 Go compiler가 itable 을 체크해서 원
하는 type이 맞는지 비교하는 코드를 생성해줌.
23. type assertion
• value := x.(int)
• type을 명시적으로 지정
• 맞지 않는 type으로 assertion을 하면 panic! (runtime error)
• 따라서 type switch와 같이 쓰는 것이 일반적
switch x.(type) {
case int:
value := x.(int)
…
case float64:
value := x.(float64)
…
24. reflect package
• run-time reflection 기능 제공
• reflect 패키지는 앞서 살펴본 type switch & type
assertion 에 해당하는 기능들과 여러가지 부가 기능을
가지고 있음.
• reflect 패키지의 기능들은 편리하기는 하지만, type
switch & type assertion에 비해 더 무거운 연산들이 동
반될 수 있으므로 고성능 어플리케이션 작성시에는 세심
하게 사용할 필요가 있음.
26. array
• var x [10]int // 길이가 10인 int형 배열 선언
• x := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
// 생성과 동시에 초기화
• x := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
// 배열 길이가 10으로 자동으로 설정됨
• y := x // 새로운 배열에 대입시 값 전체가 복사됨
27. slice
• Python의 list와 쓰임새가 유사함.
• var x []int // 선언
• x := make([]int, 5, 10) // 길이(length)는 6, 용량(capacity)은 10
• 길이 : index로 접근할 수 있는 범위 / 용량 : 실제 할당된 data array 공간
• x := make([]int, 5) // 용량은 생략 가능
• x := []int{0, 1, 2, 3, 4} // 생성과 동시에 초기화
• x = append(x, 1) // 새로운 값 추가
x = append(x, 1, 2, 3) // 여러 값을 동시에 추가도 가능
28. slice 내부 구현
• slice의 내부 구현에는 앞서 살펴본 array가 사용됨
• slice 생성시 지정된 용량만큼의 data array를 생성하고
해당 array에 대한 pointer를 가짐.
• 이 구현을 제대로 이해하는 것이 중요!
ptr
*Elem
len
int
cap
int
[]int
[5]int
29. slice 내부 구현 (2)
• x := []int{0, 1, 2, 3, 4} // 길이가 5인 slice 생성
• x = append(x, 1) // 해당 slice에 새로운 값을 추가하면?
• append는 slice 용량을 먼저 확인하고 용량이 넘치면 새로운 data array
allocation 후 값을 추가한다. (용량이 남아 있으면 바로 값만 대입.)
• 기존 slice 용량이 5 이므로 새로운 allocation이 발생!
• 다행히 append 할때마다 새로 allocation 하지는 않고 future growth
를 고려하여 필요한 용량의 2배를 할당.
• append를 매우 빈번하게 할 예정이라면 용량을 예측해서 미리 지정하
면 성능에 도움이 됨.
30. slice 내부 구현 (3)
• array는 새로운 변수에 대입시 값이 모두 복사되던데, slice도 혹시?
• slice는 앞서 살펴본 바와 같이 실제 data array에 대한 pointer 이다.
따라서 대입시 pointer만 복사된다.
• x := []int{0, 1, 2, 3, 4}
y := x // y와 x는 같은 data array를 참조. y의 데이터 조작시 x도 변
경됨.
ptr
*Elem
len
int
cap
int
[]int
[5]int
31. slice 내부 구현 (4)
• slice는 아래와 같이 부분 slice 생성이 가능하다. (slicing)
x = x[2:4]
이때는 내부적으로 어떻게 동작할까?
• slice는 앞서 살펴본 바와 같이 실제 데이터 array에 대한 pointer 이다.
slicing시에도 데이터 array는 그대로 존재하고 해당 데이터를 가리키는
pointer를 가진 slice가 생성된다.
ptr
*Elem
len
int
cap
int
[]int
[5]int
32. map
• Python의 dict와 쓰임새가 유사함.
• hash table 구현
• var x map[string]int // 선언 (key type : string / value type : int)
• x := make(map[string]int) // slice와 마찬가지로 make로 할당 가능
• x := map[string]int{“foo”: 1, “bar”: 2} // 할당과 동시에 초기화
• x[“new”] = 2 // 새로운 key로 값 대입
x[“foo”] = 4 // 기존 키의 key의 값 변경
• y := x // slice와 마찬가지로 데이터에 대한 pointer만 복사됨. 따라서 y
의 데이터 조작시 x도 변경됨.
33. map key 존재 여부 체크하기
• map에 존재하지 않는 key를 조회하게 되면 각 type의 zero value가
리턴됨. (int => 0, string => “”, bool => false 등)
x := map[string]int{“foo”: 1, “bar”: 2}
value := x[“hello”] // value = 0
• 또는, 아래와 같은 형태로 key 존재 여부 체크도 가능함.
value, ok := x[“hello”] // value = 0 (zero value) , ok = false
• if 문에서는 initialization statement를 key 존재 여부 체크 가능.
if value, ok := x[“hello”]; ok {
34. map 사용시 주의사항
• Concurrency
• map은 여러 goroutine에서 접근시 동시성을 보장하지 않
음.
• map을 여러 goroutine에서 접근할 때는 sync.RWMutex
사용 필요
• Iteration order
• for range loop로 데이터를 가져올때 순서를 보장하지 않
음.
36. struct
• Python의 class와 유사하게 사용 가능
• 선언
type Accounting struct {
Symbol string
Precision int
Thousand string
Decimal string
Format string
}
• 할당
accounting := Accounting{Symbol: "$", Precision: 2}
37. struct method
• class 가 없는 대신 struct에 method 연결 가능
type Accounting struct {
Symbol string
Precision int
Thousand string
Decimal string
Format string
}
func (accounting *Accounting) FormatMoney(value interface{}) string {
…
}
• method 호출
accounting := Accounting{Symbol: "$", Precision: 2}
accounting.FormatMoney(1234567)
39. panic
• run-time error
• Python의 Exception과 유사
• Python의 Exception 처럼 직접 발생시키는 것도 가능
panic(“unsupported type”)
• panic 발생시 적절하게 handling 하지 못하면 어플리케
이션이 중단됨.
40. recover
• defer - 함수 종료 직전에 실행. defer를 여러번 호출하면 LIFO로 실
행
• First Class Function => 익명 함수 호출 가능
• func handler() {
defer func() {
if err := recover(); err != nil {
// panic handling
}
}()
…
}
42. package
• 소스코드 첫줄에 package명 명시
package accounting
• Python의 module 과 다르게 파일명은 아무런 역할도 하지 않는다.
• 패키지 내부에 있는 함수, 변수, 상수들은 아래 규칙에 따라 역할이 결정됨.
• 첫 글자가 대문자이면 외부에서 import시 접근 가능
• 첫 글자가 소문자이면 package 내부에서만 접근 가능
• 심지어 struct의 경우에는 struct 이름 첫글자가 대문자여도 필드 이름이 소문자이
면 외부에서 접근 못함. 외부에서 접근이 필요한 필드들은 대문자를 사용해야 한다.
type Timedelta struct {
Days, Seconds, Microseconds, Milliseconds, Minutes, Hours, Weeks
time.Duration
}
43. package 공유
• github 에 repo 생성시 아래 명령어로 바로 패키지 다운로드
및 설치 가능 (bitbucket 등 다른 저장소도 지원)
go get github.com/leekchan/accounting
• 처음에는 좋아 보였으나, PyPI에 비해 단점이 많음.
• 무조건 master branch 최신 커밋 소스를 다운로드
• 기능 개발 및 테스트 후 원하는 시점에 versioning을 하고
릴리즈 할 수가 없음
• 해당 단점을 보완하는 다양한 오픈소스 라이브러가 생겨나
고 있는 중
45. gofmt
• formatting을 style guide에 맞춰서 알아서 해주는
gofmt 라는 기능을 bult-in 으로 제공
• 덕분에, 일단 코드를 쓰고 커밋하기 전에 gofmt을 한번
실행시켜 주면 style guide에 맞춰서 아름답게 formatting
이 됨.
• Python에서 PEP 8 준수를 위해 많은 linter들이 있지만
Go에서는 이미 built-in 기능인 gofmt가 끝판왕.