0519-Go(4)

망지·2022년 5월 19일
0
post-custom-banner

함수

4. defer

  • 정리작업을 수행하는 함수 지정
  • 현재 코드 블록이 끝날 때 자동으로 실행
  • defer는 여러번 사용될 수 있다 -> 나중에 defer된 함수가 먼저 실행됨(LIFO)
  • defer가 적용된 함수 중 반환값이 있는 함수의 반환값은 따로 읽을 방도가 없다.
  • defer와 이름 지정된 반환값

5. 값에 의한 호출을 사용하는 Go

  • Call by Value: 인자나 반환값은 복사된다
  • cf.) Call by Reference: 주소가 복사된다
  • 기본 타입, 구조체는 call by value
    • 파라미터로 넘어온 맵에 대한 변경은 원본에도 적용
  • 슬라이스
    • 길이 조정 외의 모든 조작이 원본에도 적용
  • 맵과 슬라이스는 포인터로 구현이 되었기 때문에 원본도 변경되는 것

포인터

1. 빠른 포인터 입문

  • 포인터란?
  • 값이 저장된 메모리의 위치 값(주소)를 저장하는 변수
    빅엔디안 방식
    0/0/0/10
    0/1/2/3
  • 주소 연산자(&)

  • 간접 연산자(*, dereferencing operator)

  • 모든 포인터는 어떤 타입을 가리키던간에 항상 같은 크기

  • 포인터의 제로 값: nil

    • 슬라이스, 맵, 함수, 채널, 인터페이스의 제로 값: nil
  • nil은 숫자 0이 아닙니다.

    • nil을 숫자로 변경/변환하거나 숫자를 반대로 변환할 수는 없다.
  • 포인터 dereferencing 전에 nil인지 확인할 필요 있다.

  • 포인터 타입

    • 포인터가 가리키는 값의 타입
    • 포인터가 어떤 타입의 값을 가리키는지 나타냄
    • 포인터 변수를 선언할 때 주로 사용
    • 타입 이름 앞에 *
    • cf.) 포인터 역참조: 변수 이름 앞에 *
x := 10
var pointerToX *int
pointerToX = &x 
  • 내장 함수 new()

    • 포인터 변수 생성
    • 해당 타입의 제로 값을 가리키는 포인터 반환
  • 기본 타입의 리터럴이나 상수는 주소가 없으므로 주소연산자를 사용할 수 없다.

    • 헬퍼 함수를 사용하여 이 문제를 해결하자

2. 포인터를 두려워 말라

  • Java의 데이터 타입
  • 원시 타입(Primitive Type): 8개
    : byte, short, int, long, float, double, bool, char: 값 그 자체, 객체가 아님, call by value
  • 클래스: 객체를 참조 변수로 참조해서 작업, call by reference
    : 원시 타입의 클래스: Byte, Short, Integer, Long, Float, Double, Boolean, Character
  • Go는 변수를 1)call by value로 할지 2)call by reference로 할지 선택할 수 있다.
    • 1) 함수에 변수를 그냥 넘기는 것
    • 2) 함수에 변수의 포인터를 넘기는 것

3. 포인터는 변경 가능한 파라미터를 가리킨다

  • 비 포인터 타입: 기본타입, 배열, 구조체 => 원본의 불변성
  • 포인터: 함수로 전달되면 포인터의 복사본이 생성 => 원본에 닿을 수 있다. 수정할 수 있다.

4. 포인터는 최후의 수단

  • 포인터
    • 데이터 흐름 이해를 어렵게 한다
    • GC에게 추가 작업 부하를 건다 (포인터를 이용하면 주로 힙을 이용)
      : 가비지는 힙에 생성

5. 포인터로 성능 개선

  • 포인터는 모든 데이터 타입을 함수로 전달할 때 상수 시간이 걸린다.
    • 주소를 함수에 전달하므로, 모든 데이터 타입의 주소 길이는 같다.
  • 대략 1메가 바이트 전달 기준으로
    • 이상이면 포인터로 전달
    • 이하면 값 전달

6. 제로 값과 값없음의 차이

  • 0, ‘ ‘ vs. NULL, ‘’ ⇒ Go: nil
    값이 있음 vs. 값이 없음

  • 포인터를 이용하여 변수나 구조체의 항목의 값이 제로 값인지 없는 값인지 구분하는데 사용

  • 할당되지 않은 변수나 구조체 항목에 nil 포인터를 사용

  • 또한, 포인터는 변경가능함을 나타내므로 함수에서 nil 포인터를 직접 반환하는 것보다 콤마 OK 관용구를 사용하자

  • nil 포인터를 함수의 파라미터나 구조체의 항목의 값으로 담아서 함수의 인자로 넘기면 nil 포인터를 통해서는 값을 저장할 수 없으므로 함수 안에서 값을 설정(간접 연산자 *를 사용하는 것)할 수가 없음을 명심

7. 맵과 슬라이스의 차이

8. 버퍼 슬라이스

  • 메모리 용도에 따른 구분
    • 버퍼(buffer)
    • 캐시(cache)
    • 풀(pool)

9. 가비지 컬렉션 작업량 줄이기

  • 버퍼를 이용하면 GC의 부하를 줄일 수 있다
  • 가비지(Garbage)
    • 더 이상 어떤 포인터도 가리키지 않는 데이터

타입, 메서드, 인터페이스

1. Go의 타입

  • 내장 타입
  • 기본 타입, 복합 타입
  • 구조체를 이용한 사용자 정의 타입
  • 구체적인 타입(구체 타입, concrete type)
    • cf.) abstract type
      : abstract = general, super, 미완성(상속)
      <-> concrete = specific, sub, 완성(상속)

2. 메서드

  • 타입(type)을 위한 메서드
    • 반드시 패키지 블록 레벨에서 정의해야 함
  • 리시버(receiver)
    • func 키워드와 메서드 이름 사이에 리시버_이름 타입을 괄호 감싸서 정의
    • 리시버 식별자는 관례적으로 타입 이름의 짧은 약어인 첫 문자를 사용

2.1 포인터 리시버와 값 리시버

  • 결정하는 규칙 (p.183)
    • 메서드가 리시버를 수정 => 반드시 포인터 리시버 사용
    • 메서드가 nil 인스턴스를 처리할 필요 => 반드시 포인터 리시버 사용
    • 메서드가 리시버를 수정하지 않음 => 값 리시버 사용 가능
    • 이것은 타입에 선언된 다른 메서드에 따라 결정
    • 같은 타입에 다른 리시버가 포인터 리시버라면 리시버를 수정하지 않는 메서드라도 포인터 리시버 사용 <= 일관성을 위해

기타

SQL

  • DML -> I,U,D, Merge, S
  • DDL(Database Object Definition Language) -> C, A, D
  • DCL 권한, 트랜잭션
profile
꾸준히, 차근차근
post-custom-banner

0개의 댓글