본문 바로가기
프로그래밍/기타

[Go] Java 개발자의 GoLang 튜토리얼 - Interface와 Duck Typing

by 사바라다 2023. 10. 2.

개요

Java에서의 Interface는 기능적인 설계를 추상화하고 특정 기능을 강제적으로 구현하게 만듬으로써 다형성과 같은 설계적인 이점을 가져가기 위한 언어적인 특징입니다. 우리는 Java에서의 Interface를 통해서 설계적인 추상화를 할 수 있고 상황에 따라 캐스팅하여 다형성(polymorphism)을 충족시킬수도 있습니다.

Go에서도 interface가 있습니다. 하지만 Java에서의 interface와는 결이 유사하면서도 조금 다릅니다. Go에서의 Interface는 형태를 강제하지 않습니다. 반대로 Interface와 동일한 어떠한 형태를 띄고 있으면 이것을 Interface의 하나의 구현으로 보는 Duck Typing의 형태를 띄고 있습니다.

이러한 부분이 이해가 잘 가지 않으실 수 있습니다. 오늘은 Go에서의 Interface와 Duck Typing에 대해서 조금 더 자세히 알아보는 시간을 가져보도록 하겠습니다.

Duck typing

Duck Typing 이란 "만약 어떠한 것이 두발로 걷고 꽥꽥 소리를 내고 날개가 있으면 그것을 Duck(오리)이다" 라는 개념을 적용하는 것입니다. 즉, 기존의 Java와 같은 Interface 방식은 Interface를 선언 후 명시적으로 class에 implement 키워드를 이용하여 해당 class가 interface를 구현해야한다는것을 명시합니다. 하지만 Duck Typing을 적용하면 Interface에 있는 메서드를 모두 구현하면 그것은 해당 Interface를 구현한 것과 동일하다라는 인식되는 것으로 적용 되어지게 됩니다.

이러한 Interface의 컨셉을 Duck Typing이라고하며 루비(Ruby), 파이썬(Python), 그리고 Go와 같은 언어에서 사용하고 있는 Type System 중 하나입니다.

장점

  • 따로 Interface를 지정할 필요가 없고, 사용할 메서드를 작성하면 되기 때문에 더 적은 코드와 복잡한 상속 구조가 필요없음. 따라서 보일러플레이트 코드가 없어도 되기 때문에 개발 시간을 줄여 줄 수 있음

단점

  • 대부분의 이러한 동적 언어는 문제를 런타임에 판별하기 때문에 서비스 중에 오류가 발견될 수 있음

이러한 단점을 예방하기 위해서는 테스트 코드 작성을 사전에 진행해서 안전함을 확인할 필요가 있습니다. 하지만 Go의 경우 이러한 판별이 런타임이 아닌 컴파일 타임에 일어납니다. 따라서 위의 단점은 없다고 봐도 무방합니다. 그래서 go에서는 duck typing이라는 용어도 사용하지만 structural typing 이라는 용어를 사용하여 설명합니다.

Go의 Interface 사용 (structural typing)

보통 이러한 Duck Typing은 python과 같은 동적언어에서 주로 사용합니다만 Go는 정적언어임에도 Duck Typing을 이용한 interface를 구현하고 있습니다. 아래에서 예제를 보도록 합시다.

type Speaker interface {
  Say(string)
}

위코드에서 Speaker라는 interface를 선언했습니다. 해당 Interface에는 Say(string)이라고하는 메서드를 포함하고 있습니다. 위의 코드에서 우리는 interface의 선언은 type {{이름}} interface로 하고 중괄호안에 메서드를 선언하면 되는것을 알 수 있습니다.

그러면 interface의 실제 구현은 어떻게 하는지 아래 코드로 확인해보겠습니다.

type Person struct {
  name string
}

func (p *Person) Say(message string) {
  log.Println(p.name+":", message)
}

interface는 struct 또는 value type에 구현할 수 있습니다. 즉, 커스텀 type에서 구현할 수 있다고 보시면됩니다. 코드에서 보시는 것 처럼 Java와는 다르게 implemetation을 명시적으로 선언하지 않는것을 확인하실 수 있습니다. Person Type에 Speaker interface의 메서드의 스펙을 구현하였을 뿐입니다. 이렇게만 하더라도 해당 interface를 구현하였다는 것으로 판별되는데 이것이 Go의 Duck Typing입니다.

실제로 그러면 아래 코드에서 테스트해보도록 하겠습니다.

func SpeakAlphabet(via Speaker) {
  via.Say("abcdefghijklmnopqrstuvwxyz")
}

func main() {
  mat := new(Person)
  mat.name = "Mat"
  SpeakAlphabet(mat)
}

Person 객체를 먼저 생성합니다. 그리고 SpeakAlphabet이라는 함수를 interface인 Speaker 타입으로 아규먼트를 받아서 Speaker가 가지고 있는 Say 메서드를 호출하는 간단한 구조입니다. SpeakAlphabet 함수의 아규먼트 타입이 Speaker 이기에 Person 타입인 mat이 정상적으로 동작한다면 Person Type은 Speaker Type으로 판단되어진다는 것을 기대할 수 있습니다.

결과는 아래와 같습니다. 에러없이 정상적으로 아래처럼 출력되는것을 알 수 있었습니다. 이를 통해서 정상적으로 Speaker interface를 구현한 하위 타입으로 인정받는것을 확인할 수 있었습니다.

Mat:abcdefghijklmnopqrstuvwxyz

마무리

오늘은 Go 언어의 Interface의 Duck Typing이라는 Type System에 대해서 알아보았습니다.

감사합니다.

참조

https://en.wikipedia.org/wiki/Duck_typing

https://medium.com/@matryer/golang-advent-calendar-day-one-duck-typing-a513aaed544d

댓글