Golang 정리(6)-인터페이스

강다빈·2026년 7월 30일

golang 공부

목록 보기
10/11

0. 용어 정리

  • 타입(type): Go에서 type 키워드를 사용하여 기본 타입 재정의 또는 구조체 정의를 할 수 있음.
    • 기본 타입 재정의(커스텀 타입): type Won int 처럼 재정의 할 수 있음. 다른 타입과 대입이나 연산이 금지(int와 Won 타입을 가진 변수끼리 연산X), 메서드 연결이 가능함.
    • 구조체 정의: type Person struct { Name String }처럼 정의할 수 있음, 메서드 연결 가능.
  • 함수: 독립적으로 기능을 수행.
type Person struct { Name string }

// 일반 함수: Person 구조체를 매개변수로 받음
func PrintNameFunc(p Person) {
    fmt.Println(p.Name)
}

// 호출 방식
PrintNameFunc(p)
  • 메서드: 리시버를 붙여서 특정 타입의 기능으로 귀속시킴. 이때 리시버 선언 방식에 따라 내부 값 변경 여부가 결정됨.
    • 값 리시버 (p Person): 구조체의 값을 복사해서 가져옴, 메서드 내부에서 값을 변경해도 원본 구조체의 값은 변하지 않음.
    • 포인터 리시버 (p *Person): 구조체의 메모리 주소를 가져옴, 메서드 내부에서 값을 변경하면 원본 구조체의 값이 실제로 변경됨.
package main

import "fmt"

type Person struct {
	Name string
}

func (p Person) PrintNameMethod() {
	fmt.Println(p.Name)
}

// 값 리시버: 원본 변경 불가
func (p Person) ChangeNameValue(newName string) {
	p.Name = newName
}

// 포인터 리시버: 원본 변경 가능
func (p *Person) ChangeNamePointer(newName string) {
	p.Name = newName
}

func main() { 

	p := Person{Name: "kdb"} 

	// 1. 값 리시버 호출 (복사본을 수정하므로 원본 변화 없음)
	p.ChangeNameValue("kdv")
	p.PrintNameMethod() // 출력: kdb

	// 2. 포인터 리시버 호출 (Go 컴파일러가 &p로 자동 해석하여 원본 수정)
	p.ChangeNamePointer("kdv")
	p.PrintNameMethod() // 출력: kdv
}
  • 인터페이스: 특정 타입(구조체, 커스텀타입)이 가져야하는 메서드들의 집합,
    • 암묵적 구현: implements 키워드 없이 특정 타입이 인터페이스에 정의된 메서드를 모두 구현하기만 하면 자동으로 인터페이스를 만족함.
    • 다형성: 하나의 객체나 메서드가 여러가지 타입을 가질 수 있는 성질, 명령은 하나인데 객체마다 다르게 행동
type Speaker interface {
    Speak() string
}

1. 인터페이스 다형성 코드 예시

특정 타입이 인터페이스에 정의된 메서드를 모두 구현하면 명시적 선언 없이 암묵적으로 인터페이스를 구현한 것으로 인정함.(이를 Duck Typing이라 함)

아래 코드는 구조체와 커스텀 타입이 모두 인터페이스의 메서드를 구현해서 암묵적으로 인터페이스를 만족하므로 MakeSounds(s Speaker) 함수의 매개변수인 인터페이스 자리에 구조체와 커스텀 타입을 넣을 수 있음.

package main

import "fmt"

// 1. 인터페이스 정의 (자격 요건)
// "Speak() 메서드를 가진 모든 타입은 Speaker로 인정한다."
type Speaker interface {
    Speak() string
}

// 2. 일반 구조체 생성 및 메서드 구현
type Dog struct{}

func (d Dog) Speak() string {
    return "멍멍!"
}

// 3. 커스텀 타입 생성 및 메서드 구현 (기본형 int 기반)
type hotdog int

func (h hotdog) Speak() string {
    return "나는 뜨거운 개다!"
}

// 4. 인터페이스를 매개변수로 받는 함수
func MakeSound(s Speaker) {
    fmt.Println(s.Speak())
}

func main() {
    myDog := Dog{}
    myFood := hotdog(1)

    // Dog와 hotdog는 형태가 완전히 다르지만,
    // 둘 다 Speak()를 할 줄 알기 때문에 Speaker로 취급됩니다.
    MakeSound(myDog)  
    MakeSound(myFood) 
}

2. 인터페이스 변수 사용 예시

변수 자체를 인터페이스로 정의하고 값을 할당하면 새로운 기술이 도입될 때 기존 코드를 많이 바꾸지 않고 변수만 다른 것으로 바꿀 수 있음.

아래 코드는 db를 인터페이스로 정의하여 MySql 구조체 사용에서 PostgreSQL 구조체 사용으로 바뀌어도 다른 메소드 사용 코드를 수정하지 않고 db 변수 수정만 하면 됨.

package main

import "fmt"

// 1. 인터페이스 정의 (자격 요건 상자)
// "Save()와 Connect() 메서드를 가진 타입은 모두 Database로 취급한다"
type Database interface {
	Connect()
	Save(data string)
}

// ---------------------------------------------------
// 2-A. 첫 번째 구체적인 타입: MySQL
type MySQL struct {
	host string
}

func (m MySQL) Connect() {
	fmt.Printf("[MySQL] %s 서버에 성공적으로 연결되었습니다.\n", m.host)
}

func (m MySQL) Save(data string) {
	fmt.Printf("[MySQL] 데이터 저장 완료: '%s'\n", data)
}

// ---------------------------------------------------
// 2-B. 두 번째 구체적인 타입: PostgreSQL (나중에 새로 추가됨)
type PostgreSQL struct {
	host string
	port int
}

func (p PostgreSQL) Connect() {
	fmt.Printf("[PostgreSQL] %s:%d 서버에 성공적으로 연결되었습니다.\n", p.host, p.port)
}

func (p PostgreSQL) Save(data string) {
	fmt.Printf("[PostgreSQL] 데이터 저장 완료: '%s'\n", data)
}

// ---------------------------------------------------

func main() {
	// 3. 변수를 인터페이스 타입으로 선언! (다용도 상자 준비)
	// 아직 이 안에는 아무것도 없습니다 (nil).
	var db Database

	fmt.Println("--- 서비스 초기 (MySQL 사용) ---")
	
	// 인터페이스 변수에 MySQL 구조체를 할당
	db = MySQL{host: "192.168.1.100"}
	
	// 여기서부터는 db가 MySQL인지 신경 쓰지 않고 인터페이스의 메서드만 호출합니다.
	db.Connect()
	db.Save("user_001")


	fmt.Println("\n--- 6개월 뒤 (PostgreSQL로 교체) ---")
	
	// db 변수가 '인터페이스'이기 때문에, 코드를 엎을 필요 없이 알맹이만 스윽 갈아 끼웁니다.
	db = PostgreSQL{host: "10.0.0.5", port: 5432}
	
	// 아래 코드는 위와 동일하지만, 이제는 PostgreSQL의 메서드가 실행됩니다!
	db.Connect()
	db.Save("user_001")
}

참고: https://velog.io/@chappi/Go%EB%A5%BC-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90-10%EC%9D%BC%EC%B0%A8-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%9E%80-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EC%A0%95%EC%9D%98

profile
하루살이

0개의 댓글