Skip to content

Instantly share code, notes, and snippets.

@deep-diver
Last active June 13, 2021 23:53
Show Gist options
  • Save deep-diver/1ee8a21893bb8fcccf6a9de37e8e27e1 to your computer and use it in GitHub Desktop.
Save deep-diver/1ee8a21893bb8fcccf6a9de37e8e27e1 to your computer and use it in GitHub Desktop.
learning-go
/* shadowing
왜 shadowing 이라고 하나?
- 그림자로 가리우듯, 앞서 등장한 변수의 값을, 동일한 이름을 가진 지역적 변수가 가려버린다.
- 그래서 앞서 등장한 변수를 전혀 접근할 수 없게 되어버린다.
- 심지어 패키지 이름으로 장난치는것도 가능하다. 그러면, shadowing 된 영역에서는 해당 패키지 접근 자체가 불가능하다.
*/
func main() {
x := 10
if x > 5 {
fmt.Println(x)
x := 5
fmt.Println(x)
}
fmt.Println(x)
}
/*
shadowing을 감지해서 알려주는 도구 "shadow"
$ go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest
$ shadow ./...
Makefile 룰에 추가해두는것이 좋다
- golangci-lint 에서 이것도 이미 지원하나? (하는듯)
*/
// 이딴것도 가능
fmt.Println(true)
true := 10
fmt.Println(true)
// 출력 결과
// true
// 10
/*
For Loop (4 ways)
- C-style
for i := 0; i < 10; i++ {}
- condition-only
i := 1
for i < 100 {}
- infinite for
for {}
- for-range
for i, v := range vals {}
*/
// iterating over maps

Shadowing

func main() {
    x := 10
    if x > 5 {
        fmt.Println(x)
        x := 5
        fmt.Println(x)
    }
    fmt.Println(x)
}

왜 shadowing 이라고 하나?

  • 그림자로 가리우듯, 앞서 등장한 변수의 값을, 동일한 이름을 가진 지역적 변수가 가려버린다.
  • 그래서 앞서 등장한 변수를 전혀 접근할 수 없게 되어버린다.
  • 심지어 패키지 이름으로 장난치는것도 가능하다. 그러면, shadowing 된 영역에서는 해당 패키지 접근 자체가 불가능하다.

shadowing을 감지해서 알려주는 도구 "shadow"

$ go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest
$ shadow ./...
  • Makefile 룰에 추가해두는것이 좋다
    • golangci-lint 에서 이것도 이미 지원한다.

For loops

4 ways

  • C-style
for i := 0; i < 10; i++ {}
  • condition-only
i := 1
for i < 100 {}
  • infinite for
for {}
  • for-range (여기 안에서 조작되는 v는 카피된 것이다)
for i, v := range vals {}

iterating over maps

m := map[string]int{
    "a": 1,
    "c": 3,
    "b": 2,
}

for i := 0; i < 3; i++ {
    fmt.Println("Loop", i)
    for k, v := range m {
        fmt.Println(k, v)
    }
}

iterating over strings

samples := []string{"hello", "apple_π!"}
for _, sample := range samples {
    for i, r := range sample {
        fmt.Println(i, r, string(r))
    }
    fmt.Println()
}

두 번째 문자열 관련 출력 결과

0 97 a
1 112 p
2 112 p
3 108 l
4 101 e
5 95 _
6 960 π
8 33 !

레이블링

func main() {
    samples := []string{"hello", "apple_π!"}
outer:
    for _, sample := range samples {
        for i, r := range sample {
            fmt.Println(i, r, string(r))
            if r == 'l' {
                continue outer
            }
        }
        fmt.Println()
    }
}

Switch

for 반복문 내에 위치한 switch 문에서, for 반복문을 원큐에 탈출하고싶다면 레이블링 기법을 쓰면 좋다.

func main() {
loop:
    for i := 0; i < 10; i++ {
        switch {
        case i%2 == 0:
            fmt.Println(i, "is even")
        case i%3 == 0:
            fmt.Println(i, "is divisible by 3 but not 2")
        case i%7 == 0:
            fmt.Println("exit the loop!")
            break loop
        default:
            fmt.Println(i, "is boring")
        }
    }
}

blank switch

가능하면 피하는게 좋다.

goto

너무 중구난방 메뚜기식 널뛰길르 방지하기 위해 두 가지 제한 사항을 둔다.

  1. 변수 선언된 부분을 건너뛸 순 없다
  2. 블록 내부로 건너뛸 순 없다.

아래는 두 경우를 모두 보여주는 예제이다.

func main() {
    a := 10
    goto skip
    b := 20
skip:
    c := 30
    fmt.Println(a, b, c)
    if c > a {
        goto inner
    }
    if a < b {
    inner:
        fmt.Println("a is less than b")
    }
}

일종의 try-catch-final 처럼 쓸 수 있다. 쓰기 나름인데, 어찌되었든 예측 가능한 수준으로 작성하면 된다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment