정상우
hELLO.
정상우
전체 방문자
347,952
오늘
1,037
어제
691
  • hELLO. (120)
    • 컴퓨터과학 (4)
      • 알고리즘 & 자료구조 (4)
    • 언어 & 프레임워크 (63)
      • Go (23)
      • PHP & Laravel (40)
    • 웹 (7)
    • 블록체인 (12)
      • 메인넷 (9)
      • 암호화폐 플랫폼 (3)
    • 포트폴리오 (10)
    • 칼럼 (19)
      • 에세이 (4)
      • 개발자스럽게 살기 (13)
      • 회고 (2)
    • 티스토리 (5)

블로그 메뉴

  • ⚡ 개발자 이력서
  • 🌟 깃허브
  • 💻 강의
  • ✨ 예제코드
  • ⭐ 브런치
  • 태그 클라우드
  • 방명록

공지사항

  • 2차 도메인을 설정했습니다 ✨

인기 글

  • [Laravel] 라라벨 프레임워크⋯
    2021.06.10
    [Laravel] 라라벨 프레임워크⋯
  • 'REST' 를 보다 'RESTful' 하게⋯
    2021.08.14
    'REST' 를 보다 'RESTful' 하게⋯
  • JWT(JSON Web Token)의 개념부⋯
    2021.07.29
    JWT(JSON Web Token)의 개념부⋯
  • 깃허브를 포트폴리오로 쓰려면⋯
    2021.12.25
    깃허브를 포트폴리오로 쓰려면⋯
  • 암호화폐 트레이딩 봇을 만들었⋯
    2021.05.12
    암호화폐 트레이딩 봇을 만들었⋯

태그

  • 라라벨
  • 블록체인
  • Algorithm
  • php
  • 개발 리뷰
  • 프로그래머스
  • go
  • 개발
  • 포트폴리오
  • 코딩테스트

최근 댓글

  • 공유해주셔서 감사합니다:)) 덕⋯
    wanderlust_sol
  • 감사합니다 ~~ :)
    정상우
  • 고맙습니다 :)
    정상우
  • 자료 받으면서 원래 댓글 잘 안⋯
    뷰스토리_
  • 다크모드 지원하는 스킨 찾고⋯
    PilTok

최근 글

  • 개발자와 엔지니어, 그 사이에서
    2022.05.10
    개발자와 엔지니어, 그 사이에서
  • 아임포트(Iamport)로 결제기능⋯
    2022.04.03
    아임포트(Iamport)로 결제기능⋯
  • 아임포트(Iamport)로 결제기능⋯
    2022.04.01
    아임포트(Iamport)로 결제기능⋯
  • [Laravel] 카페24 호스팅에 라⋯
    2022.03.29
    [Laravel] 카페24 호스팅에 라⋯
  • 2021년 회고―, 성찰
    2021.12.31
    2021년 회고―, 성찰

티스토리

hELLO · Designed By 정상우.
정상우

hELLO.

언어 & 프레임워크/Go

Go: 인터페이스와 타입 단언 (Interface, Type Assertion)

2020. 12. 4. 00:07

인터페이스

인터페이스는 이기종간 기능을 약속하여 서로 다른 기기일지라도 오직 기능적인 관점에서 일관성을 유지하기 위해 사용한다. 같은 개발자라도 가지고 있는 기술에 따라 기술 스택이 달라지지만, 코딩이라는 기능은 가질 수 있는 것처럼 말이다.

 

인터페이스는 아래와 같이 정의하는데, Go 에서는 구조체에 정의하는 메서드에 대해 인터페이스를 사용하는 것을 명시하지 않는다. 인터페이스는 타입으로 선언하며 Develop 이라는 인터페이스는 코딩이라는 기능을 가질 수 있음을 말한다. 인터페이스는 실질적인 구현에 대해서는 이야기하지 않고, 오직 그 기능이 가능한 지에 대해서만 신경쓴다.

type Develop interface {
	Coding()
}

조건에 만족하려면

인터페이스를 만족하기 위한 조건은, 메서드를 가진 구조체가 인터페이스에 정의된 메서드를 충실하게 구현하고 있을 때를 말한다. Developer 구조체는 Coding() 이라는 메서드를 구현함으로써 Develop 인터페이스를 만족한다. 따라서 Develop 타입을 가진 변수에 대해 할당을 해줄 수 있게되는 것이다. 이렇게 인터페이스를 사용하게 되면 구현에 상관없이 오직 기능적인 관점에서 프로그램을 추상화하고 접근할 수 있다.

package main

import "fmt"

type Develop interface {
	Coding()
}

type Developer struct {
	Languages []string
}

func (d Developer) Coding() {
	for _, l := range d.Languages {
		fmt.Println(l)
	}
}

func main() {
	d := Developer{[]string{"Go, PHP, Javascript"}}
	d.Coding()
}

외부 의존성 줄이기

인터페이스 타입을 사용하여 함수나 메서드 파라매터의 타입으로 지정할 수 있다. 이렇게 하면 해당 인터페이스를 구현하고 있는 구체 타입을 받을 수 있다.

package main

import "fmt"

type Develop interface {
	Coding()
}

// ...

func Work(developer Develop) {
	developer.Coding()
}

func main() {
	d := Developer{[]string{"Go, PHP, Javascript"}}
	Work(d)
}

하지만 여기서 문제가 발생하는데, 인터페이스 타입으로 하는 경우, 구체 타입에 인터페이스에 선언된 메서드 이외에 다른 메서드가 있다면, 해당 메서드는 함수 내에서 일반적으로 호출할 수 없다. Work() 함수에서 developer 파라매터에 대해 OtherMethod() 메서드를 호출하려 들지만, Develop 인터페이스에는 해당 메서드가 없어서 에러가 난다.

package main

import "fmt"

// ...

func (d Developer) OtherMethod() {
}

func Work(developer Develop) {
	developer.Coding()
	//developer.OtherMethod() // -> Error
}

// ...

타입 단언

타입 단언을 사용하면 위에서 발생한 문제를 해결할 수 있다. 인터페이스 타입을 구체 타입으로 변환하고 싶은데, 일반적인 타입 변환으로는 불가능하다. 따라서 새로운 문법인 타입 단언을 사용해야 하는데, 이것은 인터페이스 타입이지만 넘어오는 값이 특정 타입인 경우에 대해 대응할 수 있다.

// ...

func Work(developer Develop) {
	developer.Coding()
	if developer, ok := developer.(Developer); ok {
		developer.OtherMethod()
	}
}

// ...

조건문을 자세히 살펴보자. developer.(Developer) 라는 형태로 사용하여 인터페이스 타입을 구체 타입으로 바꿀 수 있고, ok 에 변환 여부가 반환된다. 만약 developer 로 넘어온 값이 Developer 타입으로 변환할 수 없다면, 타입 단언은 실패하여 조건에 부합하지 않으므로 OtherMethod() 메서드는 실행하지 않는다.

포인터 리시버

인터페이스의 메서드를 구현할 때 포인터 리시버를 사용한다면, 인터페이스 타입을 가진 변수에 구체 타입을 할당할 때 주소 값으로 할당해야 올바르게 실행할 수 있다.

package main

import "fmt"

// ...

func (d *Developer) Coding() {
	for _, l := range d.Languages {
		fmt.Println(l)
	}
}

func main() {
	var d Develop = &Developer{[]string{"Go, PHP, Javascript"}}
	d.Coding()
}

빈 인터페이스

빈(empty) 인터페이스는 어떨 때 사용할 수 있을까? 애초에 인터페이스가 비어있다는 것이 무슨 말일까? fmt.Println() 과 같은 함수에 보면 다음과 같이 시그니처가 되어있는 모습을 볼 수 있다. 파라매터로 가변인자를 받으며, 타입은 interface{} 라고 되어있다.

$ go doc fmt Println
package fmt // import "fmt"

func Println(a ...interface{}) (n int, err error)
    Println formats using the default formats for its operands and writes to
    standard output. Spaces are always added between operands and a newline is
    appended. It returns the number of bytes written and any write error
    encountered.

interface{} 라고 표현되는 빈 인터페이스를 사용하면 모든 값을 받아서 처리할 수 있다. 하지만 메서드를 바로 사용할 수는 없으며 그러려면 타입 단언을 사용해야 한다. 이러한 빈 인터페이스는 상황에 따라 유용하게 쓸 수 있지만 만능은 아니라는 점을 기억해두자.

    '언어 & 프레임워크/Go' 카테고리의 다른 글
    • Go: 고루틴과 채널 (go-routine, chan)
    • Go: 에러와 패닉 (panic, recover)
    • Go: 구조체 (메서드, 임베딩, 캡슐화)
    • Go: 맵 (Map)
    go, 인터페이스, 타입 단언
    정상우
    정상우
    과거의 배움으로 현재를 바꾸고 미래를 만듭니다. #25+2살 #INFJ #개발자 #브런치작가
    댓글쓰기
    다음 글
    Go: 에러와 패닉 (panic, recover)
    이전 글
    Go: 구조체 (메서드, 임베딩, 캡슐화)
    • 이전
    • 1
    • ···
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • ···
    • 120
    • 다음

    티스토리툴바