프로그래밍Go 개발자

Go에서 사용자 정의 타입과 메서드를 어떻게 구현하고 사용하는지, 정의 시 주의해야 할 점은 무엇인지요?

Hintsage AI 어시스턴트로 면접 통과

답변.

이해 배경:

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를 변경합니다. }

빈번한 오류 및 안티 패턴

  • alias/new type을 잘못 이해하여 alias에 메서드를 추가할 수 있다고 생각함.
  • "setter"에 대해 값 수신자를 사용하여 작동하지 않는 코드를 얻음.
  • 내장 메서드가 자동으로 사용자 정의 타입으로 전이될 것이라고 기대함.

실생활 사례

부정적인 사례

프로그래머가 type MySlice []int를 생성하고, []int와 같은 메서드(예: append)가 MySlice 타입에서 작동할 것이라고 기대했습니다. 결국, 메서드가 없다는 것이 밝혀졌고, MySlice를 []int로 직접 사용할 수 없습니다.

장점:

  • 처음에는 재사용이 편할 것 같았습니다.

단점:

  • 예기치 않은 호환성 오류와 메서드와 관련된 불편함을 겪었습니다.

긍정적인 사례

type Counter int가 정의되고 Inc 메서드가 제공되어 프로그램의 여러 부분에서 공통 로직을 사용하고 반복 코드를 피할 수 있었습니다.

장점:

  • 로직의 명확한 캡슐화. 테스트하기 쉬움.

단점:

  • 내장 타입 int에서 넘어오지 않기 때문에 특정 보조 함수를 수동으로 구현해야 했습니다.