220518

jo1132·2022년 5월 18일
0
post-thumbnail

4. 블록, 섀도, 제어 구조

4.1 블록(block)

  • 선언문이 있는 각각의 공간
  • 관련 있는 문장을 묶은 것

식별자의 스코프(scope)

  • 식별자의 Lifecycle(생명주기)
    • 블록 내에서 선언/정의될 때 식별자가 생성
    • 블록이 끝날 때, 식별자가 제거됨.
  • 즉, 블록 내에서만 해당 식별자를 사용할 수 있고,
    블록 밖에서는 해당 식별자를 접근할 수 없다.

패키지 블록

  • 함수 외부에 선언된 것들이 속한다.
  • :=은 사용 불가
  • 대문자로 시작하는 식별자는 패키지 외부에 노출(expose)된다.
  • 노출된 식별자는 점 연산자를 통해 접근
  • .go 파일이 여러개 이더라도, package 이름이 같으면 같은 패키지 블록에 포함된다.

파일 블록

  • .go 파일에 선언된 것들
  • import로 포함된 파일

함수 블록

  • 로컬 변수: 매개변수(파라미터), 반환 변수도 포함
  • 모든 중괄호는 새로운(다른) 블록을 정의
  • 제어 구조도 자체의 블록을 가진다.

유니버스 블록

  • 기본 타입, 내장 함수, ture/false와 같은 미리 선언된 식별자가 정의된 블록
  • 다른 모든 블록을 포함하는 블록
  • 따라서 다른 블록에 의해 섀도잉될 가능성이 높다.

식별자 접근

  • 외부 블록에서는 내부 블록의 요소(식별자)에 접근 불가
  • 내부 블록에서는 자신과 외부 블록의 요소에 접근 가능

    4.1.1 섀도잉 변수

    섀도잉 (shadowing)

  • 외부 블록과 내부 블록의 식별자가 같은 경우 내부 블록의 식별자로 처리
  • 내부 식별자에 의해 외부 식별자가 그림자에 가려 보이지 않음
    • x가 10으로 선언되었지만, if문 안에서 내부의 로컬변수로 초기화되어, 5가 되었다. if문 밖으로 나오니 다시 10으로 출력되었다.
    • 즉, :=은 블록 내에서는 새로운 지역변수로 취급할 수 있어, 사용을 조심해야 한다.

:= 연산자

  • 여러 변수를 :=연산자로 초기화 할 때,
    • 현재 블록에서 선언된 변수들만 재사용된다.

임포트된 패키지가 섀도잉되지 않도록 주의

  • 임포트한 패키지 이름과 같은 식별자를 선언하지 말 것

4.2 if 문

  • 조건을 괄호로 감쌀 순 있지만, 감싸지 않는 것이 일반적이다.
  • if 블록이나 else 블록내에서만 사용가능한 변수를 if 또는 else에서 바로 선언하는 방법
    • 한번만 사용한다면 변수에 담지 않아도 작동 된다.

4.3 for 문

for 문의 4가지 패턴

4.3.1 완전한 for 구문

  • C 언어와 동일한 방식의 for
  • 변수 초기화는 반드시 :=을 사용한다.
  • for 에서 선언된 변수도 if처럼 섀도잉 문제가 발생 가능하다.
  • 선언부는 한번만 실행
  • 조건부가 참 일 경우에만 for블록 실행, 거짓이면 for문 종료
  • 증감부는 forㅡㄹ록 실행이 끝나고 다시 2로 가기전에 실행

4.3.2 조건식만 사용하는 for문

  • for문을 while문처럼 사용 가능 하다.

4.3.3 for문을 이용한 무한루프 && 4.3.4 break와 continue

  • for문에 조건을 두지 않고 그냥 사용하는 것으로 무한루프를 돌릴 수 있다.
    • 이때 python과 같이 continue, break로 제어할 수 있다.

4.3.5 for-range문

  • range함수도 사용할 수 있다. range함수는 python의 enumerate함수와 비슷하게 사용 된다.
  • 내장 타입의 요소(문자열, 배열, 슬라이스, 맵)을 순회하며 루프 수행.

range가 두개의 값을 반환

  • (index, value)쌍
  • Go에서는 반환되는 값을 사용할 의도가 없다면 _(underscore)로 받는다. (Python과 같은 개념)

키 값만 순회하는 대표적인 예

  • 맵 타입을 집합 타입으로 사용한 경우
  • 맵의 값보다는 유니크한 키 값이 중요 => 집합(셋)

맵을 for range로 순회

  • 요소를 처리하는 순서가 일정하지 않다. (보안 이슈)
  • Python도 사전은 순서없는 자료형이기 때문에 비슷하다고 할 수 있다.

문자열을 for-range 순회

  • string 문자열은 하나의 문자를 byte로 가지고 있다.
  • 룬을 순회하는 것으로 type이 int32로 나온다.
  • 그러나 index는 한글을 넘어갈때 3개씩 늘어남을 볼 수 있다. 오는건 byte로 오는 것이다.

for-range의 값은 복사본

  • for-range값으로 원본을 수정할 수 없다.

레이블링(labeling)

  • 레이블: 프로그램 코드 위치에 이름 붙인 것
  • break, continue, goto문의 대상이 됨.
  • continue, break, goto에서 반복문을 빠져나오 때, 레이블로 이동하여 반복문이 계속된다.
    • 위 코드는 l이 나올때 반복문을 끊고, 다음 문장을 출력하게되는 코드다.

4.4 switch 문

  • switch, case, default, [break]
  • switch의 fall-through란?
    • break문이 없으면 만날때까지 다른 case의 내용도 실행
    • GO에서는 fall-through를 사용하려면 따로 활성화 해야한다.
      • 그러나 fall-through를 사용해아 한다면, 로직을 재구성하거나 case문 간에 의존성을 제거해 보도록 하자.
  • 다른 언어의 switch
    • fall-through 기능이 존재한다.
  • 그러나 GO는 fall-through가 기본적으로 금지, fall-through키워드로 활성화
    • [SYNTAX]
      switch (selector | confition) {
      case value|condition :
      문장1
      문장2
      ....
      case :
      case :
      ......
      }
  • 여기서 size변수는 switch문 안에서만 사용되는 지역변수로 사용되었다.
  • 위 코드에서는 switch case문으로 여러 문장을 출력하다가, 7에 도달하면, switch문과 동시에 반복문까지 한번에 탈출하기 위해 loog라벨링을 사용하였다.

4.5 공백 스위치


  • case에 불리언 결과(조건식, 불값을 반환하는 함수)를 사용한다.
  • selector 없음

5. 함수 선언과 호출

  • python과 같이 함수는 1급객체이며, 파라미터 전달, 반환 등이 가능하다.
  • main 함수
    • 프로그램 진입점
    • 실행 파일을 만들려면 필요
    • 인자 X
    • 반환값 X
  • 함수 선언
      1. func 키워드
      1. 함수 이름
      1. 입력 파라미터: 반드시 타입 명시 (GO는 정적 언어)
      1. 반환값의 타입
      • 함수의 시그니쳐
  • return 키워드로 값을 반환한다.
  • 여러 입력 파라미터가 같은 타입이라면 콤마로 파라미터를 구별하고 타입은 마지막에 기술할 수 있다.

5.1.1 이름이 지정된 파라미터(named parameters)와 선택적 파라미터 대응

  • GO는 키워드 파라미터(=named parameter)를 지원하지 않음
  • 선택적 파라미터 : 파라미터 기본값 x
  • GO는 함수를 호출할 때 함수에서 정의한 파라미터를 생략할 수 없음
    • 구조체를 사용하면 named parameter 및 선택적 파라미터 방식을 간접적으로 실현

5.1.2 가변 입력 파라미터와 슬라이스

  • 임의 개수의 입력 파라미터 처리
  • 가변 파라미터는 반드시 함수의 입력 파라미터 목록에서 마지막에 위치
  • 타입 이름 앞에 ....
  • 가변 파라미터는 함수 내에서는 해당 타입의 슬라이스 이다.

5.1.3 다중 반환값

  • Python에서는 여러값이 한번에 반환되면, 하나의 튜플로 묶여서 받을 수 있지만,
  • GO에서는 여러값이 한번에 반환되면, 여러개의 값으로 받아줘야 한다.
    • 만약 변수가 부족하다면 남은 값은 버려지게 된다.
  • GO에서는 Error를 반환할 수 있어, 보통 본문에서 에러를 확인할 수 있도록, 마지막에 에러를 반환해준다.
  • 함수 정의시 반환값의 타입을 콤마로 구분하고 괄호로 묶어준다.
  • return시 반환값을 괄호로 묶지 않는다.
  • 일반적으로 다중 반환값을 받을 때는 := 사용
  • 10을 5~0까지의 수로 나누고 몫과 나머지를 구하는 프로그램이다.
    • 분모가 0이 될때, divide by zero 에러 메세지와 함께 exit status 1코드가 출력된 것을 볼 수 있다.

5.1.4 다중 반환값은 다중 값

  • 다중 반환값은 개별 변수로 받아야 함
  • 하나의 변수로 받으면 에러

5.1.5 반환되는 값 무시

  • 함수의 반환값 개수와 받는 개수가 다르면 컴파일 에러가 출력된다.
    • _(underscore)로 에러값을 무시할 수 있다.
  • 아예 받지 않으면 에러가 나오지 않는다. 그러나 제대로 실행되는지 알 수 없다.

5.1.6 이름이 지정된 반환값(naked return)

  • 함수 정의 시 반환 값 타입뿐만 아니라 반환값 파라미터 선언
  • 해당 함수의 로컬 변수로 간주.
  • 코너 케이스
      1. 섀도잉 문제 : 반환값을 리턴하면서, 섀도윙 문제로 인한 같은 이름변수의 다른 값이 반환 되는 문제를 방지하기 위해 반환값에 미리 이름을 지정한다.
    • divAndRemainder 함수에서는 0으로 나눌수 없다는 에러가 들어가 반환될 줄 알았지만, 반환된것은 nil이었다. 그 이유는 if문 안에서 섀도잉으로 로컬변수 err이 바뀐것이고, 밖 err은 바뀌지 않은 것이다.

5.1.7 빈 반환 (blank return)

  • return 문에 반환값을 사용하지 않은 것
      1. 반환값이 없는 함수
      1. 이름 지정된 반환값을 반환하고자 할 때
      • 이 때, return을 생략하면 컴파일 에러

5.2 함수는 값이다.

  • 함수는 일급 객체이다.
    • 표현식의 일부로 표현할 수 있다.
    • 변수에 저장할 수 있고, 인자로 넘길 수 있으며, 반환값으로 넘길 수 있다.
  • 함수를 Map에 정의하여 2차원 문자열 슬라이스로 정의된 연산을 하는 프로그램
  • 결과
    • 오류처리는 아마추어와 프로를 구분짓는 요소이다.
    • 오류처리를 잘 해놓지 않으면 언제 에러가 날지 모른다.

5.2.1 함수 타입 선언

  • GO는 강타입 정적 타입 언어이므로
    • 함수를 저장하는 변수는 해당 함수의 타입으로 선언되어야 함.
    • 함수 타입: type 키워드로 정의
  • [SYNTAX]
    type 함수타입명 함수시그니처(함수 이름과 파라미터 이름 제외)
  • 함수 타입 선언으로 위 opMap함수를 이렇게 정의할 수 있다.
    • type opFuncType func(int, int)
    • var opMap = map[string]opFuncType { ....}

5.2.2 익명 함수

  • 익명함수를 사용하지 않을 때,
  • 이름 없는 함수 => 재사용하지 않겠다. = 한번만 사용한다.
  • 변수에 저장할 용도가 아니므로 인라인으로 작성한다.

5.3 클로저 (closure)

  • 함수 내부에 선언된 함수 = 내부 함수 (inner function)
  • 외부 함수에 의해 반환되는 내부 함수, 이 내부 함수는 외부 변수를 참조하는 내부 함수가 반환된 것.
  • 객체지향에서의 제네릭과 비슷하다.
  • Python에서는 데코레이터에서 클로저를 사용한다.

5.3.1 파라미터로 함수를 전달

  • sort.Slice에서 익명함수로 각 비교 조건이 되는 원소를 비교하여 boolean을 반환하는 함수를 인자로 보내주었다.

5.3.2 함수에서 함수 반환

  • 이것이 JAVA 혹은 Python에서 말하는 클로저이다.
profile
Talking Potato

0개의 댓글