구조체에 메서드 연결하기


이재홍 http://www.pyrasis.com 2014.12.17 ~ 2015.02.07


Go 언어에는 클래스가 없는 대신 구조체에 메서드를 연결할 수 있습니다.

  • func (리시버명 *구조체_타입) 함수명() 리턴값_자료형 { }

이번에도 앞에서 만든 사각형(Rectangle) 구조체를 사용하겠습니다.

type Rectangle struct {
	width  int
	height int
}

//          ↓ 리시버 변수 정의(연결할 구조체 지정)
func (rect *Rectangle) area() int {
	return rect.width * rect.height
	//     ↑  리시버 변수를 사용하여 현재 인스턴스에 접근할 수 있음
}

func main() {
	rect := Rectangle{10, 20}

	fmt.Println(rect.area()) // 200
}

실행 결과

200

함수를 정의할 때 func 키워드와 함수명 사이에 리시버 정의 부분이 추가되었습니다. 이렇게 하면 메서드 안에서는 리시버 변수를 통해 현재 인스턴스의 값에 접근할 수 있습니다. 그리고 구조체 인스턴스에 . (점)을 사용하여 연결된 메서드를 호출합니다.

리시버로 정의한 변수에는 메서드가 포함된 구조체의 인스턴스 포인터가 들어옵니다. 따라서 리시버 변수를 통해서 현재 인스턴스의 필드 값을 가져오거나 변경할 수 있습니다. (즉, 리시버는 C++의 this 포인터 또는 Java의 this 키워드와 비슷합니다).


그림 30-1 구조체 메서드와 리시버

함수에 구조체 형태의 매개변수를 넘기는 방식과 마찬가지로 리시버 변수를 받는 방법도 포인터와 일반 구조체 방식이 있습니다.

//           ↓ 포인터 방식
func (rect *Rectangle) scaleA(factor int) {
	rect.width = rect.width * factor   // 포인터이므로 원래의 값이 변경됨
	rect.height = rect.height * factor // 포인터이므로 원래의 값이 변경됨
}

//          ↓ 일반 구조체 방식
func (rect Rectangle) scaleB(factor int) {
	rect.width = rect.width * factor   // 값이 복사되었으므로 원래의 값에는 영향을 미치지 않음
	rect.height = rect.height * factor // 값이 복사되었으므로 원래의 값에는 영향을 미치지 않음
}

func main() {
	rect1 := Rectangle{30, 30}
	rect1.scaleA(10)
	fmt.Println(rect1) // {300 300}: rect1에 바뀐 값이 들어감

	rect2 := Rectangle{30, 30}
	rect2.scaleB(10)
	fmt.Println(rect2) // {30 30}: rect2는 값이 바뀌지 않음
}

실행 결과

{300 300}
{30 30}

scaleA 메서드는 리시버 변수로 구조체 포인터를 받았기 때문에 원래 값이 변경되지만, scaleB 메서드는 구조체를 그대로 받으면서 값이 복사되었으므로 원래의 값에는 영향을 미치지 않습니다.

메서드를 작성할 때 구조체 인스턴스의 값을 변경한다면 포인터 형태로 받고, 일반적인 상황에서는 리시버 변수를 값 형태로 받는 것이 좀 더 명확합니다.

리시버 변수를 사용하지 않는다면 _ (밑줄 문자)로 변수를 생략할 수 있습니다.

func (_ Rectangle) dummy() { // _로 리시버 변수 생략
	fmt.Println("dummy")
}

func main() {
	var r Rectangle
	r.dummy() // dummy
}

실행 결과

dummy

저작권 안내

이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.
  • 블로그, 게시판 등에 퍼가는 것을 금지합니다.
  • 비공개 포스트에 퍼가는 것을 금지합니다.
  • 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
  • 링크 및 SNS 공유는 허용합니다.

Published

01 June 2015