Go에서 적합한 리시버 타입 결정하기

Go를 사용하다 보면 메서드 리시버로 값을 사용할지, 포인터를 사용할지 고민하는 경우가 많습니다. 최근 읽은 책에서 이에 대해 명확한 기준을 제시한 내용이 있어 공유하려 합니다. 대부분 익숙한 내용일 수 있지만, 이렇게 체계적으로 정리하니 고민을 줄이고 새로운 관점도 얻을 수 있어 유용했습니다.

리시버가 반드시 포인터여야 하는 경우

  • 리시버의 값을 변경해야 하는 경우

가장 단순한 케이스로, 메서드에서 리시버의 값을 수정해야 할 때입니다. 예를 들어, 리시버가 슬라이스인 경우 메서드 내에서 원소를 추가하거나 수정해야 한다면 포인터 리시버가 필요합니다.

  • 복제할 수 없는 필드가 있는 경우

리시버에 복제할 수 없는 필드가 포함되어 있다면 반드시 포인터로 사용해야 합니다. 책에서는 sync 타입을 예로 들어 설명하고 있습니다.

포인터 리시버가 바람직한 경우

  • 리시버가 큰 구조체일 때

리시버가 큰 객체라면 포인터를 사용하여 복사 작업으로 인한 성능 저하를 방지할 수 있습니다. 단, 적당한 크기의 구조체라면 상황에 따라 값 리시버를 사용할 수도 있습니다. 빈번히 호출되는 메서드라면 성능 측정을 통해 복사의 비용을 평가하는 것이 좋습니다.

리시버가 반드시 값이어야 하는 경우

  • 불변성을 보장해야 하는 경우

리시버의 상태가 메서드 호출 중에 절대로 변경되지 않아야 할 때 값 리시버를 사용합니다.

  • 특정 타입의 리시버

리시버가 map, function, 또는 channel 타입일 경우에는 반드시 값 리시버를 사용해야 합니다. 다른 경우 포인터를 사용하면 컴파일 에러가 발생합니다.

값 리시버가 바람직한 경우

  • 변경이 필요 없는 슬라이스

리시버가 슬라이스이고 변경할 필요가 없다면 값 리시버를 사용하는 것이 적합합니다.

  • 작고 가변 필드가 없는 구조체

리시버가 크기가 작은 배열 또는 구조체이며, 가변 필드가 없다면 값 리시버가 적절합니다.

  • 기본 타입 리시버

리시버가 int, float64, string과 같은 기본 타입일 경우 값 리시버를 사용하는 것이 자연스럽습니다.

Go를 사용하는 개발자라면 **100 Go Mistakes**를 읽어볼 것을 추천합니다. 이 책은 실수를 줄이고 효율적인 코드를 작성하는 데 큰 도움이 될 것입니다.

이 내용이 도움이 되었기를 바랍니다. 추가로 다듬거나 보완할 부분이 있다면 말씀해주세요! 😊