Slice 와 Map 은 값을 여러개 자질 수 있는 타입이다. 그러나 선언한 타입과 같은 타입만 저장해야 하는 문제가 있다. 또한 class 와 같이 다양한 멤버 변수를 가질 수 없다.
그래서 Go 에서는 다양한 값을 가질 수 있도록 Struct 타입을 지원한다.
Struct
struct 의 를 만들려면 type 키워드, struct명, struct 키워드로 만든다. 그리고 그 안에 다양한 변수를 포함할 수 있으며 {} 로 묶어주면 된다.
type 으로 struct 를 선언했으면 그 자체가 하나의 type 이 된다. 그럼 var 로 새로운 만든 type을 활용하여 변수 선언을 할 수 있다. 아래와 같이 name 과 age 를 필드로 갖는 person 이라는 새로운 타입을 선언하고 jina 와 jamie 라는 변수를 만들 수 있다.
변수 선언만 한 struct 내의 필드들은 zero 값을 갖는다.
person 타입의 변수를 초기화 할 때는 {} 로 초기화 할 수 도 있다.
package main
import "fmt"
func main() {
type person struct {
name string
age int
}
var jina person
fmt.Println(jina)
jamie := person{}
fmt.Println(jamie)
}
--- output ---
{ 0}
{ 0}
혹은 값을 지정하여 초기화 할 수 있다.
값을 지정하여 초기화할 때는 json 타입으로 변수: 값 으로 지정하거나 값 으로 지정할 수 있다. 변수 사이는 , 로 구분하며, 마지막 변수 끝에도 , 를 넣어야 한다.
Go 에서는 타입을 선언할 때는 { 앞에 공백을 넣지만, 값을 초기화할 때는 { 앞에 공백을 넣지 않는다. 또한 타입을 선언할 때는 필드 사이에 , 가 없지만, 값을 초기화 할 때는 필드값 사이에 , 를 넣는다.
jina := person{
name: "Jina",
age: 21,
}
fmt.Println(jina)
jamie := person{
"Jamie",
18,
}
fmt.Println(jamie)
--- output ---
{Jina 21}
{Jamie 18}
초기화는 아래와 같이 할 수 도 있다.
단, jina[”age”] 와 같이 인덱싱을 통한 접근은 지원하지 않는다.
var jina person
jina.name = "Jina"
jina.age = 21
// jina["age"] = 21 // 인덱싱은 지원하지 않음
fmt.Println(jina.name)
--- output ---
Jina
Anonymous struct
type 이 없는 struct 도 가능하다.
이 때는 type 키워드를 쓰지 않는다.
아래와 같이 바로 jina 라는 변수를 struct 형태로 지정하고 . 을 통해 값을 지정할 수 있다. 혹은 {} 를 사용하여 jamie 변수를 선언하면서 초기 값을 지정할 수 있다.
var jina struct {
name string
age int
}
jina.name = "Jina"
jina.age = 21
fmt.Println(jina)
jamie := struct {
name string
age int
}{
name: "Jamie",
age: 18,
}
fmt.Println(jamie)
--- output ---
{Jina 21}
{Jamie 18}
Struct 비교
go 에서는 type 이 같으면 대입(=), 비교(==) 를 할 수 있다. 하지만 type 이 다르면 비교나 대입을 할 수 없다.
하지만 type 을 convert 하여 맞춰 준다면 대입, 비교가 가능하다.
jina 와 jina2 는 type 이 같고 필드 값도 같다. 그래서 비교를 하면 true 값이 나온다.
하지만 jamie 는 jina 와 type 이 같지만 필드 값이 달라서 비교를 하면 false 값이 나온다.
jina := person{
name: "Jina",
age: 21,
}
jina2 := person{
name: "Jina",
age: 21,
}
fmt.Println(jina == jina2)
jamie := person{
name: "Jamie",
age: 18,
}
fmt.Println(jina == jamie)
--- output ---
true
false
새로운 anotherPerson type 을 만들어서 살펴보자.
아래와 같이 jina 는 person type 이고 jamie 는 anotherPerson type 이므로 서로 type 이 달라서 비교나 대입을 하면 에러가 난다.
type anotherPerson struct {
name string
age int
}
jina := person{
name: "Jina",
age: 21,
}
fmt.Println(jina)
jamie := anotherPerson{
name: "Jamie",
age: 18,
}
fmt.Println(jina == jamie)
--- output ---
./main.go:88:19: invalid operation: jina == jamie (mismatched types person and anotherPerson)
이번에는 jamie 를 person type 으로 바꾸는 type converson 을 하여 비교하여 보자.
타입 변환도 잘 되고 값도 정상적으로 대입되는 것을 알 수 있다.
type anotherPerson struct {
name string
age int
}
jina := person{
name: "Jina",
age: 21,
}
fmt.Println(jina)
jamie := anotherPerson{
name: "Jamie",
age: 18,
}
jina = person(jamie)
fmt.Println(jina)
--- output ---
{Jina 21}
{Jamie 18}
한가지 중요한 점은 struct 사이에 타입 변환은 타입, 필드명, 필드 순서, 필드 갯수 가 모두 동일해야 가능하다.
그럼 type 으로 선언된 struct 와 anonymous struct 는 타입을 제외한 필드명, 필드 순서, 필드 갯수 가 같다면 대입이나 비교, 타입 변환이 가능할까?
정답은 가능하다이다.
jina := person{
name: "Jina",
age: 21,
}
fmt.Println(jina)
var jamie struct {
name string
age int
}
jamie = jina
fmt.Println(jina == jamie)
--- output ---
{Jina 21}
true
jamie := struct {
name string
age int
}{
name: "Jamie",
age: 18,
}
var jina person
jina = person(jamie)
fmt.Println(jina)
fmt.Println(jina == jamie)
--- output --
{Jamie 18}
true
사실 person(jamie) 로 타입 변환을 하지 않아도 정상적으로 동작한다.