연습 - 구조체 사용
필드 컬렉션을 하나의 구조로 나타내야 하는 경우가 있습니다. 예를 들어, 급여 프로그램을 작성해야 하는 경우 employee 데이터 구조를 사용해야 합니다. Go에서 구조체를 사용하여 레코드를 구성할 수 있는 여러 필드를 함께 그룹화할 수 있습니다.
Go에서 ‘구조체’는 임의 형식의 필드를 0개 이상 포함하고 이러한 필드를 단일 엔터티로 표현할 수 있는 ‘다른 데이터 형식’입니다.
이 섹션에서는 구조체가 필수적인 이유와 구조체를 사용하는 방법을 알아봅니다.
구조체 선언 및 초기화
구조체를 선언하려면 새 데이터 형식에 지정할 필드 목록 및 해당 형식과 struct
키워드를 사용해야 합니다. 예를 들어, employee 구조체를 정의하기 위해 다음 코드를 사용할 수 있습니다.
type Employee struct {
ID int
FirstName string
LastName string
Address string
}
그러면 다음과 같이 일반적으로 다른 형식을 사용할 때처럼 새 형식의 변수를 선언할 수 있습니다.
var john Employee
변수의 선언과 초기화를 동시에 수행하려는 경우에는 다음과 같은 방법으로 이 작업을 수행할 수 있습니다.
employee := Employee{1001, "John", "Doe", "Doe's Street"}
구조체의 각 필드에 대한 값을 지정해야 합니다. 하지만 이 경우에는 문제가 발생할 수 있습니다. 또는 구조체에서 초기화하려는 필드를 보다 구체적으로 지정할 수 있습니다.
employee := Employee{LastName: "Doe", FirstName: "John"}
이전 문에서 각 필드에 값을 할당하는 순서는 중요하지 않습니다. 또한 다른 필드에 대한 값을 지정하지 않는 경우에는 이러한 순서가 중요하지 않습니다. Go는 필드 데이터 형식에 따라 기본값을 할당합니다.
구조체의 개별 필드에 액세스하려면 다음 예제와 같이 점 표기법(.
)을 사용하여 이 작업을 수행할 수 있습니다.
employee.ID = 1001
fmt.Println(employee.FirstName)
마지막으로, 다음 코드와 같이 &
연산자를 사용하여 구조체에 대한 포인터를 생성할 수 있습니다.
package main
import "fmt"
type Employee struct {
ID int
FirstName string
LastName string
Address string
}
func main() {
employee := Employee{LastName: "Doe", FirstName: "John"}
fmt.Println(employee)
employeeCopy := &employee
employeeCopy.FirstName = "David"
fmt.Println(employee)
}
위의 코드를 실행하면 다음과 같은 출력이 표시됩니다.
{0 John Doe }
{0 David Doe }
포인터를 사용할 때 어떻게 구조체가 변경 가능한지 확인합니다.
구조체 포함
Go에서 구조체를 사용하여 구조체 내에 다른 구조체를 포함할 수 있습니다. 반복을 줄이고 공용 구조체를 다시 사용하려는 경우가 있을 수 있습니다. 예를 들어, Employee와 Contractor에 대해 다른 데이터 형식을 지정하도록 이전 코드를 리팩터링하려고 합니다. 다음 예제와 같이 공통 필드를 포함하는 Person
구조체가 있을 수 있습니다.
type Person struct {
ID int
FirstName string
LastName string
Address string
}
그런 다음, Employee
및 Contractor
와 같이 Person
형식을 포함하는 다른 형식을 선언할 수 있습니다. 다른 구조체를 포함하려면 다음 예제와 같이 새 필드를 만듭니다.
type Employee struct {
Information Person
ManagerID int
}
그러나 Person
구조체의 필드를 참조하려면 다음 예제와 같이 employee 변수의 Information
필드를 포함해야 합니다.
var employee Employee
employee.Information.FirstName = "John"
이와 같이 코드를 리팩터링하는 경우 코드가 중단됩니다. 또는 다음 예제와 같이 포함하려는 구조체와 동일한 이름을 가진 새 필드를 포함할 수 있습니다.
type Employee struct {
Person
ManagerID int
}
데모용으로 다음 코드를 사용할 수 있습니다.
package main
import "fmt"
type Person struct {
ID int
FirstName string
LastName string
Address string
}
type Employee struct {
Person
ManagerID int
}
type Contractor struct {
Person
CompanyID int
}
func main() {
employee := Employee{
Person: Person{
FirstName: "John",
},
}
employee.LastName = "Doe"
fmt.Println(employee.FirstName)
}
모든 필드를 자동으로 포함하게 되므로 Person
필드를 지정하지 않고도 Employee
구조체에서 FirstName
필드에 액세스하는 방법을 알아봅니다. 그러나 구조체를 초기화하는 경우에는 값을 할당하려는 필드를 구체적으로 지정해야 합니다.
JSON을 사용하여 구조체 인코딩 및 디코딩
마지막으로, 구조체를 사용하여 JSON에서 데이터를 인코딩 및 디코딩할 수 있습니다. Go는 JSON 형식을 매우 잘 지원하며, 표준 라이브러리 패키지에 이미 포함되어 있습니다.
구조체에서 필드 이름 이름을 바꾸는 등의 작업도 수행할 수 있습니다. 예를 들어, JSON 출력에 FirstName
은 표시하지 않고 단순히 name
만 표시하는 경우를 피하고 빈 필드를 무시하지 않으려 한다고 가정해 보겠습니다. 다음 예제와 같이 필드 태그를 사용할 수 있습니다.
type Person struct {
ID int
FirstName string `json:"name"`
LastName string
Address string `json:"address,omitempty"`
}
그런 다음, 구조체를 JSON으로 인코딩하려면 json.Marshal
함수를 사용합니다. JSON 문자열을 데이터 구조로 디코딩하려면 json.Unmarshal
함수를 사용합니다. 모든 항목을 함께 배치하고, employee 배열을 JSON으로 인코딩하고, 출력을 새 변수로 디코딩하는 예제는 다음과 같습니다.
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
ID int
FirstName string `json:"name"`
LastName string
Address string `json:"address,omitempty"`
}
type Employee struct {
Person
ManagerID int
}
type Contractor struct {
Person
CompanyID int
}
func main() {
employees := []Employee{
Employee{
Person: Person{
LastName: "Doe", FirstName: "John",
},
},
Employee{
Person: Person{
LastName: "Campbell", FirstName: "David",
},
},
}
data, _ := json.Marshal(employees)
fmt.Printf("%s\n", data)
var decoded []Employee
json.Unmarshal(data, &decoded)
fmt.Printf("%v", decoded)
}
위의 코드를 실행하면 다음과 같은 출력이 표시됩니다.
[{"ID":0,"name":"John","LastName":"Doe","ManagerID":0},{"ID":0,"name":"David","LastName":"Campbell","ManagerID":0}]
[{{0 John Doe } 0} {{0 David Campbell } 0}]