type 키워드는 새로운 타입을 정의하는 데 사용되는 중요한 키워드입니다.
기본 타입 정의
type 키워드를 사용하여 기존 타입을 기반으로 새로운 타입을 정의할 수 있습니다.
type MyInt int
type MyString string
이렇게 정의된 타입은 원래 타입과 구조적으로 동일하지만, Go 컴파일러는 이를 다른 타입으로 취급합니다.
구조체 정의
type을 사용하여 구조체를 정의할 수 있습니다.
type Person struct {
Name string
Age int
}
인터페이스 정의
인터페이스도 type 키워드로 정의합니다.
type Printer interface {
Print() string
}
함수 타입 정의
함수 시그니처를 새로운 타입으로 정의할 수 있습니다.
type MathFunc func(int, int) int
예제:
// MathFunc는 두 개의 int를 받아 하나의 int를 반환하는 함수 타입입니다.
type MathFunc func(int, int) int
// 덧셈 함수
func add(a, b int) int {
return a + b
}
// 뺄셈 함수
func subtract(a, b int) int {
return a - b
}
// MathFunc 타입의 함수를 인자로 받아 실행하는 함수
func executeMathOperation(f MathFunc, x, y int) int {
return f(x, y)
}
func main() {
// MathFunc 타입의 변수에 함수 할당
var operation MathFunc
// 덧셈 연산
operation = add
executeMathOperation(operation, 10, 5)
// 뺄셈 연산
operation = subtract
executeMathOperation(operation, 10, 5)
// 익명 함수를 직접 MathFunc로 사용
executeMathOperation(func(a, b int) int {
return a / b // 나눗셈
}, 10, 5)
}
타입 별칭 (Type Alias)
Go 1.9부터는 타입 별칭을 정의할 수 있습니다.
type MyAlias = string
MyAlias가 string의 또 다른 이름일 뿐임을 나타냅니다.
Named Type
- Named Type (MyType)은 완전히 새로운 타입입니다.
- 이는 타입 안전성을 보장하기 위함입니다.
var a int = 5
var b MyInt = 5
// a = b // 컴파일 에러: cannot use b (type MyInt) as type int in assignment
메서드 세트와 타입
Named Type을 정의할 때, 해당 타입에 대한 메서드를 정의할 수 있습니다.
type MyInt int
func (m MyInt) Double() MyInt {
return m * 2
}
이렇게 정의된 메서드는 원본 타입 (int)에는 적용되지 않고, 새로 정의된 타입 (MyInt)에만 적용됩니다.
타입 임베딩 (Type Embedding)
구조체 내부에 다른 타입을 임베드할 수 있습니다.
type Employee struct {
Person
JobTitle string
}
이 경우 Employee는 Person의 모든 필드와 메서드를 상속받게 됩니다.
타입 임베딩 (Type Embedding) 사용 시 주의사항
1. 이름 충돌
임베디드 타입과 외부 타입이 동일한 이름의 필드나 메서드를 가질 경우, 외부 타입의 필드나 메서드가 우선됩니다.
type A struct {
Name string
}
type B struct {
A
Name string // 이 필드가 A의 Name 필드를 가림
}
func main() {
b := B{A: A{Name: "Inner"}, Name: "Outer"}
fmt.Println(b.Name) // "Outer" 출력
fmt.Println(b.A.Name) // "Inner" 출력
}
2. 임베디드 포인터 타입의 nil 체크
포인터 타입을 임베드할 경우, nil 체크를 주의해야 합니다.
type A struct {
name string
}
func (a *A) Speak() {
fmt.Println(a.name) // 패닉 발생: nil 포인터 역참조
}
type B struct {
*A
}
func TestConstraint(t *testing.T) {
var b B
b.Speak()
}
마지막으로 Named type과 Type Alias를 좀 더 알아보겠습니다.
Named Type vs Type Alias
Named Type과 Type Alias의 차이점을 이해하는 것이 중요합니다.
type MyType string // Named Type
type MyAlias = string // Type Alias
타입 동일성
- Type Alias: 원본 타입과 완전히 동일한 타입으로 취급됩니다.
- Named Type: 원본 타입과 다른 새로운 타입으로 취급됩니다.
type MyString string // Named Type
type MyAlias = string // Type Alias
var s string = "hello"
var ms MyString = "hello"
var ma MyAlias = "hello"
// s = ms // 컴파일 에러
s = ma // 가능
메서드 세트
- Type Alias: 원본 타입의 모든 메서드를 그대로 사용할 수 있습니다.
- Named Type: 독립적인 메서드 세트를 가집니다.
type AgeNamed int
type AgeAlias = int
// 정상
func (a AgeNamed) IsAdult() bool {
return a >= 18
}
// 컴파일에러
// Invalid receiver type 'int' ('int' is a non-local type)
func (a AgeAlias) IsAdult() bool {
return a >= 18
}
타입 전환(Type Assertion)
- Type Alias: 원본 타입과 동일하게 취급되어 타입 전환이 필요 없습니다.
- Named Type: 명시적인 타입 전환이 필요합니다.
type AliasMyInt = int // Alias Type
var ay int = 20
var ax AliasMyInt = 10
// 직접 할당 가능
ax = ay
ay = ax
type NamedMyInt int // Named Type
var x NamedMyInt = 10
var y int = 20
// 직접 할당 불가능
// x = y // 컴파일 에러
// y = x // 컴파일 에러
// 명시적 타입 전환 필요
x = NamedMyInt(y)
y = int(x)
Named Type은 새로운 타입을 만들어 타입 안전성과 의미론적 명확성을 높이고, Alias Type은 기존 타입을 유연하게 사용할 수 있게 해줍니다.
참고
spec: embedding a type alias is confusing #17746
https://go.googlesource.com/proposal/+/master/design/18130-type-alias.md
'프로그래밍 > Golang' 카테고리의 다른 글
Golang의 struct(구조체)와 receiver(리시버) 메서드: 객체 지향적 설계의 새로운 접근 (0) | 2024.07.23 |
---|---|
Golang func 와 method (0) | 2024.07.22 |
Golang Constants(상수) (0) | 2024.07.20 |
Golang 변수와 Scope(스코프) 이해하기 (0) | 2024.07.19 |
Golang Module(모듈) 발행 가이드: GitHub에 패키지 배포 (0) | 2024.07.18 |