Go 언어 method – 업무에 사용하는 Go 언어 12

Go 언어 method는 struct에 속하는(혹은 속해있는) 함수입니다.
Go 언어에는 class가 존재하지 않고 oop를 위해 struct를 이용하게 됩니다.
oop의 특징을 struct에 도입하여 사용할 수 있도록 되어있습니다.

업무에 사용하는 Go 언어 썸네일

Go 언어 method 정의

Go 언어 method는 특정 타입에 속하는 함수로 정의되어 있습니다.
즉, Go 언어 method를 정의하려면 먼저 struct와 같이 사용자 정의 타입을 정의하고 해당 타입에 바인딩할 함수를 정의하면 됩니다.

Go 언어 method는 함수 이름 앞에 리시버(receiver)를 명시하여 특정 struct에 바인딩 할 수 있습니다.
다음 예시를 참고하여 직접 Go 언어 method를 정의해보세요.

Go
type Rectangle struct {
	Width, Height int
}

// Rectangle 타입에 Area 메서드를 정의
func (r Rectangle) Area() int {
	return r.Width * r.Height
}

func main() {
	rect := Rectangle{Width: 10, Height: 5}
	println("Rectangle Area:", rect.Area()) // 메서드 호출
}

Rectangle struct를 정의하고 면적을 구하는 area method를 정의한 예시입니다.
Go 언어 method를 호출할 때는 struct의 필드에 접근할 때와 마찬가지로 . (dot) 연산자를 사용하면 된답니다.

“method는 receiver가 있는 함수다.” 라고 기억하면 좋을 것 같네요.
메서드와 일반 함수의 차이점은 값을 꼭 전달해야 하는가 아닌가로 따지면 되겠습니다.

값 리시버와 포인터 리시버

함수에서 매개변수를 call by value, call by reference로 나눌 수 있듯이
go 언어 method는 값 리시버(Value Receiver), 포인터 리시버(Pointer Receiver)를 사용할 수 있습니다.

Go
// Rectangle 타입에 Area 메서드를 정의
func (r Rectangle) Area() int {
	return r.Width * r.Height
}

위에서 살펴본 예시를 다시 가져왔습니다.
Area method는 값 리시버를 사용했으며 값의 복사본을 사용하게 됩니다.
따라서, 다른 언어의 call by value와 동일하게 어떠한 연산의 결과를 반환하도록 작성하면 됩니다.

Go
func (r *Rectangle) Scale(factor float64) {
    r.Width *= factor
    r.Height *= factor
}

그렇다면 위 코드의 Scale method는 어떨까요?
포인터 리시버를 사용했으며 데이터에 직접 접근하여 변경이 가능하기 때문에 직접 값을 수정하도록 작성하면 되겠습니다.

Go
package main

type Rectangle struct {
	Width, Height float64
}

// Value Receiver
func (r Rectangle) Area() float64 {
	return r.Width * r.Height
}

// Pointer Receiver
func (r *Rectangle) Scale(factor float64) {
	r.Width *= factor
	r.Height *= factor
}

func main() {
	rect := Rectangle{Width: 10, Height: 5}
	println("Rectangle Area:", rect.Area())
	rect.Scale(2)
	println("Rect:", rect.Width, rect.Height)
}

위 코드와 같이 직접 값 리시버를 이용한 method, 포인터 리시버를 이용한 method를 정의하여 사용해보도록 합시다.

내부 동작

직접 사용해보시면 다른 언어와 약간 다른 점을 느끼셨을 수도 있습니다.
포인터 리시버를 method를 호출할 때 변수 앞에 * 를 붙여주어야 하는거 아닌가 하는 의문인데요.
Go 언어는 method가 포인터 리시버를 가졌다는 것을 알고 있기 때문에 편의상 알아서 해석해줍니다.

Go
rect.Scale(2) -> (&rect).Scale(2)

실제로 위와 같이 코드를 변경하여 실행해봐도 좋은 경험이 될 것 같습니다.
이에 대한 편의성은 값 리시버를 가진 method에 포인터 변수를 통해 호출해도 동일하게 적용됩니다.

다음 글에서 알아볼 내용

Go 언어 interface