메서드에 대한 컨벤션
메서드 정의 시 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 |