if • [Python] if x> 0: • [Go] if x > 0 { } • initialization statement if ok := check(); ok {
11.
for • [Python] for valuein 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 { // 무한 루프
함수 선언 • [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”
interface{} • interface는 method의집합 (단, 메서드 자체를 구현하 지는 않음.) • method가 정의되지 않은 빈 인터페이스(interface{})는 어떠한 조건도 없기 때문에 모든 type의 값 대입이 가능. • func sum (x, y interface{})
22.
type switch • switchx.(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-timereflection 기능 제공 • reflect 패키지는 앞서 살펴본 type switch & type assertion 에 해당하는 기능들과 여러가지 부가 기능을 가지고 있음. • reflect 패키지의 기능들은 편리하기는 하지만, type switch & type assertion에 비해 더 무거운 연산들이 동 반될 수 있으므로 고성능 어플리케이션 작성시에는 세심 하게 사용할 필요가 있음.
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로 데이터를 가져올때 순서를 보장하지 않 음.
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 } }() … }
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을 하고 릴리즈 할 수가 없음 • 해당 단점을 보완하는 다양한 오픈소스 라이브러가 생겨나 고 있는 중
gofmt • formatting을 styleguide에 맞춰서 알아서 해주는 gofmt 라는 기능을 bult-in 으로 제공 • 덕분에, 일단 코드를 쓰고 커밋하기 전에 gofmt을 한번 실행시켜 주면 style guide에 맞춰서 아름답게 formatting 이 됨. • Python에서 PEP 8 준수를 위해 많은 linter들이 있지만 Go에서는 이미 built-in 기능인 gofmt가 끝판왕.