Go에서 제공하는 표준 타입만 잘 써도 충분히 유연하고 빠르게 처리할 수 있다. 하지만 Go로 구현하는 코드에 필요한 모든 종류의 데이터를 직접 표현하기에는 한계가 있다. 그래서 Go 언어는 프로그래머가 원하는 타입을 정의할 수 있도록 struct를 제공한다.
다양한 타입의 변수를 묶어서 새로운 타입으로 정의하고 싶다면 구조체를 사용해야 한다. 이렇게 구조체를 구성하는 요소를 fields of the structure라 부른다.
구조체의 field는 주로 대문자로 시작한다. 소문자로 시작하면 외부에서 사용할 수 없다.
type user struct {
UserName string
Age int
}
// case 1
user := user{"chris", 10}
// case 2
user := user{UserName: "chris", Age: 10}
// case 3
user := user {
UserName: "chris",
Age: 10,
}
,로 끝나야 한다.Go에서는 구조체를 익명 타입으로 구성할 수 있다. 두 익명 타입 구조체가 동일한 field를 가지고 있어서 두 구조체의 field의 순서가 다르면 서로 대입할 수 없다.
u := struct {
name string
age int
}{
name: "chris",
age: 10,
}
Go 언어는 new keyword를 이용해 새로운 object를 할당하는 기능을 지원한다. new는 포인터를 리턴한다.
type user struct {
name string
age int
}
u := new(user)
fmt.Printf("%p: %v\n", u, u)
// 0x1400011a018: &{ 0}
Go 언어에서 type method란 특수한 receiver 인수를 받는 함수다. Type method는 일반 함수처럼 선언하되 함수 이름 앞에 특수한 매개변수가 더 나온다. 이 매개변수는 함수와 여기에 추가한 매개변수의 타입을 연결한다. 따라서 이러한 매개변수를 reciver of the method라 부른다.
type user struct {
name string
age int
}
u := user{"chris", 10}
// 일반 함수
func PrintUserAge(u user) {
u.age++
fmt.Println(u.age)
}
// 메소드 (value receiver)
func (u user) PrintUserAge() {
u.age++
fmt.Println(u.age)
}
// 메소드 (pointer receiver)
func (u *user) PrintUserAge() {
u.age++
fmt.Println(u.age)
}
위와 같이 type method는 일반 함수와 구현부는 완벽히 같다.
하지만 type method는 method이기 때문에 호출 방식이 다음과 같이 다르다.
// 일반 함수 호출
PrintUserAge(u)
// 메소드 호출
u.PrintUserAge()
value receiver는 값을 복사하여 전달하기 때문에 method 내부에서 값을 변경해도 원본 값은 변화가 없는 반면,
pointer receiver는 주소를 전달하기 때문에 method 내부에서 값을 변경하면 원본 값이 변경된다.