반응형

메서드에 대한 컨벤션

메서드 정의 시 Go에서는 아래와 같은 컨벤션을 일반적으로 따른다.

  • 리시버 인자 정의
    • 리시버 인자의 변수 이름은 리시버 타입 이름의 첫 글자를 사용한다
    • 변수는 하나의 글자로만 선언한다
  • 밸류 vs 포인터 선언
    • 값을 변경할 필요가 없는 경우에는 배류 리시버로 선언해야 하지만, 통일성을 위해서 밸류와 포인터를 섞어서 선언하지 않고 포인터로 선언한다 (참고 : Head First Go)

 

Pointer Receiver

  • Value Receiver  : 메서드 사용 시 새로운 객체를 생성할 필요가 있으면 값 타입 메서드 
  • Pointer Receiver : 메서드 사용 시 새로운 객체 생성이 아니라 값을 참조해와야하면 포인트 타입 메서드 
    • 사용하는 이유는
      • 메서드가 리시버가 가리키는 값을 수정할 수 있음
      • 각각의 메서드 call에서의 value 복사 문제를 피하기 위해서 
        => 리시버가 큰 구조체라면 이것은 더 효율적일 수 있음 
package method_interface

import "fmt"

// 메서드 사용 시 새로운 객체를 생성할 필요가 있으면 값 타임 메서드
// 메서드 사용 시 새로운 객체를 생성할 필요가 있으면 포인트 타입 메서드

type Person struct {
	Name string
	Age  int
}

func (p *Person) AddAge() {
	p.Age += 1 // value receiver
}

type Temperature float64

func (t Temperature) Up(temp float64) Temperature {
	return t + Temperature(temp) // pointer receiver
}

func Main2() {
	p1 := Person{Name: "Rob", Age: 4}

	fmt.Println("P1: ", p1)
	p1.AddAge()
	fmt.Println("P1: ", p1)

	t := Temperature(30.0)

	fmt.Println("T: ", t)
	t = t.Up(4.0)
	fmt.Println("T: ", t)
}

package main

func main(){
	method_interface.Main2()
}

 

Pointer Indirection / dereference (메서드와 포인트 역참조)

포인터를 다루는 데 있어 함수, 메서드 간의 차이가 존재 

  • 함수에 포인터 인자로 선언한 인자는 포인터 인자만 인자로 받을 수 있다
  • 메서드의 리시버 인자의 경우에는 포인터와 밸류 인자 둘 다 받을 수 있다

포인터 인자가 밸류일때?

area(r *Rectangle) 함수의 인자는 포인터 인자로 선언되어 밸류 값을 넘기면 컴파일 오류가 발생하고 포인터 인자만을 넘길 수 있다.

func area(r *Rectangle) {
	fmt.Println(r.height * r.width)
}

func Example_Indirection_Func_Pointer_Parameter() {
	r := Rectangle{
		height: 10,
		width:  3,
	}

	//area(r) //컴파일 오류 - 함수는 포인터 인자만 받을 수 있음
	area(&r)

	//Output:
	//30
}

 

r.area(), r은 포인터가 아닌 밸류 값이지만, 포인터 리시버 인자의 메서드가 호출될 때
Go에서 자동으로 r.area() -> (&r).area()로 해석을 해서 실행

func (r *Rectangle) area() {
	fmt.Println(r.height * r.width)
}

func Example_Indirection_Method_Pointer_Receiver() {
	r := Rectangle{
		height: 10,
		width:  3,
	}

	r.area()
	(&r).area()

	//Output:
	//30
	//30

}

 

리시버 인자가 밸류일때?

perimeter(r Rectangle) 함수는 밸류 인자로 선언되어 perimeter(&r) 포인터 값을 인자로 넘겨주면 컴파일 오류가 발생

func perimeter(r Rectangle) {
	fmt.Println(2 * (r.height * r.width))
}

func Example_Indirection_Func_Value_Parameter() {
	r := Rectangle{
		height: 10,
		width:  3,
	}

	//perimeter(&r) //컴파일 오류 - 함수는 value 인자만 받을 수 있음
	perimeter(r)

	//Output:
	//60
}

리시버 인자의 경우, (&r).perimeter() 호출 시 Go는 리시버 인자는 밸류 인자로 선언되어 (*r).perimeter()로 자동으로 해석해서 실행

func (r Rectangle) perimeter() {
	fmt.Println(2 * (r.height * r.width))
}

func Example_Indirection_Method_Value_Receiver() {
	r := Rectangle{
		height: 10,
		width:  3,
	}

	r.perimeter()
  (&r).perimeter()

	//Output:
	//60
	//60
}

 

메서드는 함수에 리시버 인자를 추가한 버전으로 이해하는 걸로 하자 

반응형

'Language Study > Go' 카테고리의 다른 글

[Golang]Quick sort(퀵 정렬)  (0) 2022.12.13
[Golang]bubble sort(버블 정렬)  (0) 2022.12.13
[Golang]array, slice, map  (0) 2022.12.04
[Golang]변수, 상수  (0) 2022.08.21
[Golang]클래스, 구조체, 인스턴스  (0) 2022.08.08

+ Recent posts