🔥 포인터 리시버

370자
5분

Go 언어에서는 포인터 리시버를 사용하여 메서드를 선언할 수 있습니다. 포인터 리시버란 어떤 타입 T에 대해 리시버 타입이 *T와 같은 문법을 가지는 것을 말합니다. 단, T*int와 같은 포인터 타입이 될 수 없습니다.

예를 들어, 아래 코드에서 Scale 메서드는 *Vertex 타입의 리시버를 가집니다.

func (v *Vertex) Scale(f float64) {
    v.X = v.X * f
    v.Y = v.Y * f
}
 
go

포인터 리시버를 사용하는 메서드는 리시버가 가리키는 값을 수정할 수 있습니다. 위의 Scale 메서드가 그 예시입니다. 메서드는 종종 리시버의 값을 수정해야 하므로, 포인터 리시버가 값 리시버보다 더 일반적으로 사용됩니다.

16번 줄의 Scale 함수 선언에서 *를 제거하고 프로그램의 동작이 어떻게 변하는지 살펴봅시다.

값 리시버를 사용하면 Scale 메서드는 원래의 Vertex 값을 복사한 값에 대해 동작하게 됩니다. 이는 다른 함수 인자와 동일한 동작입니다. main 함수에서 선언된 Vertex 값을 변경하려면 Scale 메서드는 반드시 포인터 리시버를 가져야 합니다.

아래는 포인터 리시버를 사용한 전체 예제 코드입니다:

package main
 
import (
    "fmt"
    "math"
)
 
type Vertex struct {
    X, Y float64
}
 
func (v Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
 
func (v *Vertex) Scale(f float64) {
    v.X = v.X * f  // 포인터 리시버 v를 통해 Vertex 구조체의 필드 X를 수정합니다.
    v.Y = v.Y * f  // 포인터 리시버 v를 통해 Vertex 구조체의 필드 Y를 수정합니다.
}
 
func main() {
    v := Vertex{3, 4}  // Vertex 구조체 변수 v를 초기화합니다.
    v.Scale(10)        // v의 Scale 메서드를 호출하여 v의 필드 값을 10배 늘립니다.
    fmt.Println(v.Abs())  // v의 Abs 메서드를 호출하여 크기를 계산하고 출력합니다.
}
 
go

위 코드를 실행하면 vX, Y 값이 각각 10배씩 늘어난 후 Abs 메서드에 의해 크기가 계산되어 50이 출력될 것입니다.

단계별 설명을 정리하면 다음과 같습니다:

  1. Vertex 구조체를 정의합니다. XY 필드를 가집니다.
  2. Vertex 타입에 대한 Abs 메서드를 값 리시버로 정의합니다. 이 메서드는 Vertex의 크기를 계산하여 반환합니다.
  3. Vertex 타입에 대한 Scale 메서드를 포인터 리시버로 정의합니다. 이 메서드는 VertexX, Y 값을 인자 f만큼 곱하여 크기를 변경합니다.
  4. main 함수에서 Vertex 변수 v를 초기값 {3, 4}로 선언합니다.
  5. v.Scale(10)을 호출하여 vX, Y 값을 10배 늘립니다.
  6. v.Abs()를 호출하여 v의 크기를 계산하고 그 결과를 출력합니다.

이렇게 포인터 리시버를 사용하여 메서드를 정의하면 메서드 내에서 리시버가 가리키는 값을 직접 수정할 수 있게 됩니다. 메서드가 리시버의 데이터를 읽기만 할 경우에는 값 리시버로도 충분하지만, 리시버의 필드를 수정해야 한다면 포인터 리시버를 사용해야 할 것입니다.