아래와 같은 Funcer
타입의 인터페이스가 있다고 하자.
type Funcer interface {
Func()
}
Funcer
를 매개변수로 받는 함수가 있다고 하자.
func funcer(f Funcer) {}
마지막으로 T
타입을 정의하자.
type T struct{}
이제 이 T
타입이 Funcer
를 충족하도록 메서드를 구현하자. 이 때, 이 메서드의 receiver
타입과 메서드를 호출하는 변수의 타입(Value
or Pointer
)에 따라 인터페이스의 충족 기준이 달라진다.
Value
func (t T) Funcer() {}
val := T{} // Value
funcer(val) // valid
ptr := &T{} // Pointer
funcer(ptr) // valid
Pointer
func (t *T) Funcer() {}
val := T{} // Value
funcer(val) // invalid!!!!!!!
ptr := &T{} // Pointer
funcer(ptr) // valid
정리하자면 이렇다.
Value
인 경우, 인터페이스의 Method Sets을 충족하려면 인터페이스가 정의하는 모든 메서드의 receiver
타입은 오직 Value
여야 한다.Pointer
인 경우, receiver
타입은 Value
든 Pointer
든 상관 없다.왜냐하면 전자의 경우 예상치 못한 결과를 야기할 수 있기 때문에 문법적으로 막아놓은 것이다.
Go 공식문서에서 설명하고 있는 예제는 아래와 같다.
var buf bytes.Buffer
io.Copy(buf, os.Stdin)
receiver
의 타입이 Pointer
라면, 이는 이 메서드를 호출함으로써 receiver
의 값이 변경될 여지가 있다는 뜻이다.
bytes.Buffer
는 Write
메서드를 Pointer receiver
로 구현하고 있는데, 당연하지만 bytes.Buffer
의 값 자체를 변경해야하기 때문이다.
io.Copy
는 두번째 매개변수의 값을 첫번째 매개변수로 복사하는 유틸함수다. 첫번째 매개변수는 io.Writer
타입의 인터페이스를 받는다.
만약 Value
타입의 변수가 Poitner receiver
로 정의된 메서드를 구현하고 있다고 여기게 되면 어떻게 될까? 즉, 이 경우 bytes.Buffer
의 Write
메서드를 &buf
가 아닌 buf
가 만족한다고 여겨지면 어떤 문제가 발생할까?(위에서도 언급했듯 bytes.Buffer
의 Write
메서드는 Pointer receiver
로 정의되어 있다.)
Go에서 모든 것은 Pass By Value로 작동하므로, 매개변수로 Value
를 넘기면 복사본이 넘겨진다. 이 복사본에 os.Stdin
의 값을 복사해봐야 아무런 의미가 없다! 어차피 io.Copy
가 종료되면 사라지기 때문이다! 이는 사용자가 절대로 기대하지 않는 동작이다.
따라서 인터페이스는 Pointer receiver
로 정의된 메서드에 대해서는 엄격하게 Pointer
타입의 변수만이 이 Method Sets을 구현한다고 본다.
(본 글은 2019-12-08에 작성한 글의 본문 내용을 옮긴 글입니다.)