이해 배경:
Go에서는 내장 타입으로는 부족한 경우가 자주 발생하며, 로직을 캡슐화하고 기능을 확장하기 위해 자신만의 데이터 타입을 정의해야 합니다. 이는 사용자 정의 타입(type) 및 메서드(func (r Receiver) MethodName())를 생성함으로써 이루어집니다.
문제:
초보 개발자들은 종종 새로운 타입을 기존 타입을 기반으로 선언하는 것의 차이를 혼동합니다. 메서드는 어떻게 올바르게 구현하나요? 복사, 값/포인터로의 전달은 어떻게 해결하나요? 가시성, 수신자 타입 및 embedded structs 작업에서 오류가 발생합니다.
해결책:
자신의 타입을 정의하기 위해 type 키워드를 사용합니다. 메서드는 수신자로 구현되며, 이는 인터페이스 작업을 위해 중요합니다.
코드 예시:
type MyInt int func (m MyInt) Double() int { return int(m) * 2 } // 구조체에 대한: type User struct { Name string Age int } func (u *User) Birthday() { u.Age++ } var u = User{"Alice", 30} u.Birthday() // Age = 31
주요 특징:
사용자 정의 타입은 기본 타입의 메서드를 상속하나요?
아니요. type MyInt int를 정의하면 MyInt는 int의 메서드를 가지지 않습니다. 예를 들어, String() 호출이 작동하지 않습니다.
타입의 별칭에 메서드를 정의할 수 있나요?
별칭(type MyType = ExistingType)에는 메서드를 추가할 수 없습니다. 메서드는 새 타입(type MyType ExistingType)에만 정의할 수 있으며 별칭에 대해서는 정의할 수 없습니다.
어떤 수신자를 사용해야 하나요: 포인터 또는 값?
메서드가 객체를 변경해야 한다면 포인터를 사용하는 것이 좋습니다. 값 수신자는 구조를 복사하므로, 구조체가 슬라이스 및 맵 속성을 포함하는 경우 예상치 못한 동작을 초래할 수 있습니다.
코드 예시:
type Counter struct { value int } func (c *Counter) Inc() { c.value++ } func main() { c := Counter{} c.Inc() // 포인터와 함께 사용해야만 메서드가 value를 변경합니다. }
프로그래머가 type MySlice []int를 생성하고, []int와 같은 메서드(예: append)가 MySlice 타입에서 작동할 것이라고 기대했습니다. 결국, 메서드가 없다는 것이 밝혀졌고, MySlice를 []int로 직접 사용할 수 없습니다.
장점:
단점:
type Counter int가 정의되고 Inc 메서드가 제공되어 프로그램의 여러 부분에서 공통 로직을 사용하고 반복 코드를 피할 수 있었습니다.
장점:
단점: