이미 정의한 무언가(타입)을 재활용하여 새로운 무언가(타입)을 만드는 것을 Embedding 이라고 한다. 이러한 방법으로는 대표적으로 상속 과 컴포지션 이 있다.
많은 언어가 이미 정의된 타입을 참고해 새로운 타입을 정의할 떄, 상속을 주로 사용하였다. 하지만 이러한 상속은 몇 가지 문제점을 가지고 있다.

컴포지션은 원래 클래스를 수정할 수 없기 때문에 개방폐쇄 원칙을 강제한다. 또한 원래 클래스가 캡슐화를 잘 지켜 만들었다면, 이를 포함하는 새로운 클래스는 원래 클래스의 내부동작에 간섭하지 못하므로 캡슐화 또한 지켜진다.
이러한 문제점에 따라, Go는 상속기능을 지원하지 않고, 오로지 컴포지션(Go Embedding) 기능만을 지원하도록 설계되었다.
type Base struct {
Name string
Age int
}
type EmbedBase struct {
Base
Price int
}
임베딩의 방식에는 두 가지 방식이 존재한다. 하나는 타입을 임베딩하는 것이고, 다른 하나는 타입의 포인터를 임베딩하는 방식이다.
위 코드에서 EmbedBase 구조체는 Base의 필드들을 모두 가지며, Price 라는 새로운 필드를 가지는 새로운 타입니다.
type Base struct {
Name string
Age int
}
type EmbedPointerBase struct {
*Base
Price int
}
EmbedPointerBase 의 첫 번째 필드를 보면 Base의 포인터를 필드로 갖는 새로운 타입이다.
이 두 방식은 객체 생성 및 전달에서 차이가 있으며, 객체 내부 변수에 어떻게 접근할 것인가에 따라 사용처가 달라질 것이다. 이전 포스팅에서도 꾸준히 나왔었지만, pass by value 와 pass by reference 의 차이처럼 말이다.
Base의 메서드가 Base의 값을 제어하고, 이때 이 Base를 임베딩한 EmbedBase 객체를 값으로 넘기는 특수한 함수를 가정하면, 함수 내부에서 Base를 조작하는 것은 외부에 영향을 주지 못 한다.
package embedding
import "fmt"
type Base struct {
Name string
Age int
}
type EmbedBase struct {
Base
Price int
}
type EmbedPointerBase struct {
*Base
Price int
}
func (b Base) printBase() {
fmt.Println(b.Name, b.Age)
}
func changeBase(baseinfo *EmbedBase) {
baseinfo.Name = "changed name"
baseinfo.Age = 3
}
func Embedding() {
baseinfo := Base{"name", 2}
embedbaseinfo := EmbedBase{baseinfo, 30000}
embedbaseinfo.printBase()
changeBase(&embedbaseinfo)
baseinfo.printBase()
}
////
name 2
name 2
위 코드에서 EmbedBase에 Base struct가 담긴 후, 해당 embedbaseinfo의 주소값을 보내서 값을 수정을 했지만, 원본인 Base에는 변화가 없는 것을 알 수 있다. 하지만 여기서 포인터를 임베딩한 struct를 이용하면 원본에 변화를 줄 수 있을 것이다.
package embedding
import "fmt"
type Base struct {
Name string
Age int
}
type EmbedBase struct {
Base
Price int
}
type EmbedPointerBase struct {
*Base
Price int
}
func (b Base) printBase() {
fmt.Println(b.Name, b.Age)
}
func changeBase(baseinfo EmbedPointerBase) {
baseinfo.Name = "changed name"
baseinfo.Age = 3
}
func Embedding() {
baseinfo := Base{"name", 2}
embedbaseinfo := EmbedPointerBase{&baseinfo, 30000}
embedbaseinfo.printBase()
changeBase(embedbaseinfo)
baseinfo.printBase()
}
////
name 2
changed name 3