A Tour of Go 4
출처 Go Tour
🚫 아래 내용은 주관적인 생각이므로 사실과 다를 수 있습니다.
Range 1
package main
import "fmt"
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
}
// 2**0 = 1
// 2**1 = 2
// 2**2 = 4
// 2**3 = 8
// 2**4 = 16
// 2**5 = 32
// 2**6 = 64
// 2**7 = 128
for 반복문에서의 range는 슬라이스 또는 맵을 순회한다
슬라이스를 대상으로 range를 사용할 때, 매 순회마다 두 값이 반환되는데,
첫번째 값은 인덱스이고, 두 번째 값은 해당 인덱스의 요소의 복사본이다
Range 2
package main
import "fmt"
func main() {
pow := make([]int, 10)
for i := range pow {
pow[i] = 1 << uint(i) // == 2**i
}
for _, value := range pow {
fmt.Printf("%d\n", value)
}
}
// 1
// 2
// 4
// 8
// 16
// 32
// 64
// 128
// 256
// 512
_를 할당해서 인덱스 또는 값을 생략할 수 있다
for i, _ := range pow
for _, value := range pow
인덱스만 사용할거라면 두 번째 변수를 생략해도 된다
for i := range pow
Exercise: Slices
package main
import "golang.org/x/tour/pic"
func Pic(dx, dy int) [][]uint8 {
result := make([][]uint8, dy)
for i := 0; i < dy; i++ {
result[i] = make([]uint8, dx)
}
for y := 0; y < dy; y++ {
for x := 0; x < dx; x++ {
switch (x * y) % 3 {
case 0:
result[y][x] = uint8((x + y) / 2)
case 1:
result[y][x] = uint8(x * y)
case 2:
result[y][x] = uint8(x ^ y)
}
}
}
return result
}
Pic 함수를 만들어보자
가로 세로 각각 입력받은 dx, dy길이의
uint8 타입 2차원 배열을 반환하면 된다
각 요소의 값들을 다르게 지정해 출력되는 이미지를 바꿀 수 있다
(x+y)/2, x*y, x^y 등의 수식을 사용하는것도 좋다
- 반복문을 통해 2차원 배열([][]uint8)의 요소들에 각각의 배열([]uint8)들을 할당해줘야 한다
- uint8(정수값)을 사용해 형변환한다
Maps
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m map[string]Vertex
func main() {
m = make(map[string]Vertex)
m["Bell Labs"] = Vertex{
40.68433, -74.39967,
}
fmt.Println(m["Bell Labs"])
}
// {40.68433 -74.39967}
맵은 키에 값을 매핑한다
맵의 기본값은 nil이고, nil 맵은 키도 없고 키를 추가할 수도 없다
make 함수는 입력된 타입의 맵(초기화되고 바로 사용가능한)을 반환한다
Map literals 1
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m = map[string]Vertex{
"Bell Labs": Vertex{
40.68433, -74.39967,
},
"Google": Vertex{
37.42202, -122.08408,
},
}
func main() {
fmt.Println(m)
}
// map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]
맵 리터럴은 기본적으로 구조체 리터럴과 비슷하지만 키가 필요하다
Map literals 2
package main
import "fmt"
type Vertex struct {
Lat, Long float64
}
var m = map[string]Vertex{
"Bell Labs": {40.68433, -74.39967},
"Google": {37.42202, -122.08408},
}
func main() {
fmt.Println(m)
}
// map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]
리터럴 요소의 타입이 최상위의 타입과 동일하다면, 타입을 생략해도 된다
Mutating Maps
package main
import "fmt"
func main() {
m := make(map[string]int)
m["Answer"] = 42
fmt.Println("The value:", m["Answer"])
m["Answer"] = 48
fmt.Println("The value:", m["Answer"])
delete(m, "Answer")
fmt.Println("The value:", m["Answer"])
v, ok := m["Answer"]
fmt.Println("The value:", v, "Present?", ok)
}
// The value: 42
// The value: 48
// The value: 0
// The value: 0 Present? false
맵 m의 요소를 업데이트 또는 삽입
m[key] = elem
요소 가져오기
elem = m[key]
요소 삭제
delete(m, key)
두 개의 값을 할당해 맵에 키가 있는지 확인
elem, ok = m[key]
맵 m에 키가 있으면 ok값은 true, 없으면 false다
맵에 키가 없으면 elem의 값은 요소 타입의 기본값이 된다
elem, ok 모두 초기화된 적이 없다면 아래와 같이 할당이 가능하다
elem, ok := m[key]
Exercise: Maps
package main
import (
"golang.org/x/tour/wc"
"strings"
)
func WordCount(s string) map[string]int {
result := make(map[string]int)
for _, v := range strings.Fields(s) {
result[v] = result[v] + 1
}
return result
}
func main() {
wc.Test(WordCount)
}
// PASS
// f("I am learning Go!") =
// map[string]int{"Go!":1, "I":1, "am":1, "learning":1}
// PASS
// f("The quick brown fox jumped over the lazy dog.") =
// map[string]int{"The":1, "brown":1, "dog.":1, "fox":1, "jumped":1, "lazy":1, "over":1, "quick":1, "the":1}
// PASS
// f("I ate a donut. Then I ate another donut.") =
// map[string]int{"I":2, "Then":1, "a":1, "another":1, "ate":2, "donut.":2}
// PASS
// f("A man a plan a canal panama.") =
// map[string]int{"A":1, "a":2, "canal":1, "man":1, "panama.":1, "plan":1}
WordCount 함수를 만들어보자
- 입력값 s string을 공백 문자 기준으로 분할해
- 단어별 출현 횟수를 맵에 담아 반환하면 된다
strings.Fields 문서가 도움이 될 것이다
Function values
package main
import (
"fmt"
"math"
)
func compute(fn func(float64, float64) float64) float64 {
return fn(3, 4)
}
func main() {
hypot := func(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}
fmt.Println(hypot(5, 12))
fmt.Println(compute(hypot))
fmt.Println(compute(math.Pow))
}
// 13
// 5
// 81
함수도 값이다
함수도 다른 변수들처럼 전달할 수 있다
함수값은 파라미터나 반환값으로 사용될 수 있다
Function closures
package main
import "fmt"
func adder() func(int) int {
sum := 0
return func(x int) int {
sum += x
return sum
}
}
func main() {
pos, neg := adder(), adder()
for i := 0; i < 10; i++ {
fmt.Println(
pos(i),
neg(-2*i),
)
}
}
// 0 0
// 1 -2
// 3 -6
// 6 -12
// 10 -20
// 15 -30
// 21 -42
// 28 -56
// 36 -72
// 45 -90
클로저(closure)는 내부함수와 밀접한 관계를 가지고 있는 주제다.
내부함수는 외부함수의 지역변수에 접근 할 수 있는데
외부함수의 실행이 끝나서 외부함수가 소멸된 이후에도
내부함수가 외부함수의 변수에 접근 할 수 있다.
이러한 메커니즘을 클로저라고 한다.
Go에서도 클로저를 사용할 수 있다
클로저에서 내부함수는 외부함수의 변수에 “bound(바운드)” 된다
예를 들면, 위 코드의 adder 함수는 클로저를 반환하고,
각 클로저는 그 자체의 sum 변수에 bound(바운드) 된다
Exercise: Fibonacci closure
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
prev := 0
next := 1
return func() int {
temp := prev
prev = next
next = temp + prev
return temp
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
// 0
// 1
// 1
// 2
// 3
// 5
// 8
// 13
// 21
// 34
클로저로 피보나치 수를 구현해보자
댓글남기기