본문 바로가기
Language/Go

Effective Go - Methods

by ocwokocw 2022. 5. 17.

- 출처: https://go.dev/doc/effective_go#methods

- Methods

메소드는 포인터나 인터페이스를 제외하고 명명된 유형에 대해 정의될 수 있다. 즉 Receiver가 반드시 구조체가 아니어도 된다.
 
예를 들어 Append라는 함수를 slice의 메소드로 정의할 수 있는데, 이렇게 하기 위해서는 우선 메소드를 묶을 수 있도록 명명된 유형을 정의해야 한다. 그리고 Receiver로 해당 형을 기술해준다.
 
type ByteSlice []byte

func (slice ByteSlice) Append(data []byte) []byte {
    // Body exactly the same as the Append function defined above.
}
 
위의 메소드는 갱신된 slice를 반환한다. 아래 코드와 같이 receiver를 ByteSlice에 대한 pointer로 변경하여 method를 정의하면 slice를 반환하지 않아도 된다.
 
func (p *ByteSlice) Append(data []byte) {
    slice := *p
    // Body as above, without the return.
    *p = slice
}
 
위의 코드를 보면 갱신된 slice를 반환하지 않았다. 대신 메소드에서 호출자의 slice를 덮어썼다. 이를 더 정성스럽게 변경하면 우리가 익숙한 io.Writer 인터페이스 형태로 변경할 수 있다.
 
func (p *ByteSlice) Write(data []byte) (n int, err error) {
    slice := *p
    // Again as above.
    *p = slice
    return len(data), nil
}
 
이제 *ByteSlice 형이 표준 인터페이스인 io.Writer를 만족하게 되었으므로 아래와 같이 Fprintf 함수에도 해당 형을 자연스럽게 사용할 수 있게 된다.
 
var b ByteSlice
fmt.Fprintf(&b, "This hour has %d days\n", 7)
 
위의 코드에서 ByteSlice 의 주소를 넘겼는데 *ByteSlice만이 io.Writer 인터페이스를 만족하기 때문이다. receiver에 대한 pointer와 value의 규칙은 value 메소드의 경우 pointer와 value 둘 다에서 실행 가능하지만, pointer method의 경우 pointer 에서만 실행이 가능하다.

 

이런 규칙은 pointer 메소드가 receiver를 수정할 수 있기 때문에 발생한다. value에서 method를 수행하면 value에 대해 호출하면 receiver 역시 value의 복사본이기 때문에 수정사항이 버려진다. 이런 경우 발생할 수 있는 실수를 방지하기 위해 앞에서 언급한 규칙을 강제한다.
 
다만 한가지 편리함을 위해 예외를 적용해주는데 value에 주소를 지정할 수 있는 경우 golang은 자동으로 주소 연산자(&)을 삽입하여 value에 대한 pointer 메소드를 실행해준다. 예를 들어 변수 b가 주소를 지정할 수 있어서 b.Write 와 같이 Write 메소드를 호출하면 compiler는 자동으로 (&b).Write로 다시 써준다.
 

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

Effective Go - Embedding  (0) 2022.05.29
Effective Go - Interfaces and other types  (0) 2022.05.26
Effective Go - Array and Slice  (0) 2022.05.08
Effective Go - New 와 Make  (0) 2022.05.07
Effective Go - Functions  (0) 2022.05.07

댓글