Golang의 구조체
Go 언어에서 구조체는 사용자 정의 데이터 유형을 생성하는 데 있어 핵심적인 역할을 합니다. 이는 Go 프로그래밍에서 가장 빈번하게 사용되는 기능 중 하나입니다.
이 글에서는 구조체의 기본 사항을 자세히 살펴보고, 실제 Go 프로그램에서 구조체를 활용하는 여러 방법을 예시와 함께 소개합니다.
자, 함께 시작해 볼까요!
소개
구조체는 서로 연관된 다양한 데이터 필드들을 묶어 하나의 단위로 관리하는 데이터 구조입니다. 여러 데이터를 함께 묶어 사용자 정의 레코드를 만들 때 유용하게 활용됩니다. 구조체는 기본 데이터 타입뿐만 아니라 다른 사용자 정의 타입(구조체 자체도 포함)을 포함할 수 있습니다.
Go 언어의 구조체는 가변적(mutable)이어서, 프로그램 실행 중에 내용을 수정할 수 있습니다.
구조체는 복잡한 데이터 구조를 생성하고 여러 모듈 간에 전달하는 데 효율적입니다. 이를 통해 코드 품질을 향상시킬 수 있습니다. 예를 들어, 함수에 10개의 매개변수를 전달하는 대신, 하나의 구조체를 전달함으로써 코드를 더 간결하고 이해하기 쉽게 만들 수 있습니다.
구조체는 type과 struct 키워드를 사용하여 선언합니다. struct 키워드 뒤에는 중괄호({})로 묶인 필드들의 집합이 옵니다. 이는 자바의 클래스와 유사하지만, 상속은 지원하지 않습니다. 구조체 선언에 대한 자세한 내용은 다음 섹션에서 다루겠습니다.
객체 지향 프로그래밍(OOP)에 익숙한 개발자라면 구조체를 클래스와 비슷하게 생각할 수 있지만, Go 언어의 구조체는 상속 개념을 포함하지 않는다는 점을 기억해야 합니다.
구조체 선언
이제 구조체의 정의와 사용 이유를 이해했으므로, 구조체를 실제로 선언하는 방법을 알아볼 차례입니다. 다음은 구조체의 기본적인 형태입니다.
type 구조체_이름 struct {
필드1 데이터_타입_필드1
필드2 데이터_타입_필드2
}
여기서 type과 struct는 키워드이며, struct는 여러 필드(데이터 타입과 함께)를 포함합니다.
실제 예시를 통해 살펴보겠습니다.
package main
import (
"fmt"
)
type 사용자 struct {
이름 string
나이 int
잔고 float32
}
func main() {
var 사용자1 사용자
fmt.Println(사용자1)
}
위 예시에서는 string, int, float32 타입의 필드를 포함하는 사용자 구조체를 정의했습니다. main() 함수에서 사용자 구조체 타입의 변수 '사용자1'을 선언하고 출력합니다. 아직 초기화하지 않았으므로 출력 결과는 각 필드의 제로(0) 값입니다. Go에서는 제로 값이 각 데이터 타입의 기본값입니다.
{ 0 0}
구조체 초기화
이전 섹션에서는 구조체를 선언하는 방법을 배웠습니다. 이제 구조체 변수에 값을 할당하거나 초기화하는 방법을 알아봅시다. 아래 코드를 확인하세요.
package main
import (
"fmt"
)
type 사용자 struct {
이름 string
나이 int
잔고 float32
}
func main() {
// 필드 이름을 사용하여 초기화
사용자1 := 사용자{
이름: "모히트",
나이: 24,
잔고: 100.0,
}
// 필드 이름 없이 초기화
사용자2 := 사용자{"니디", 21, 1000.0}
fmt.Println(사용자1)
fmt.Println(사용자2)
}
위 코드는 필드 이름을 사용하거나 사용하지 않고 두 개의 구조체를 초기화하는 방법을 보여줍니다. 출력 결과는 다음과 같습니다.
{모히트 24 100}
{니디 21 1000}
만약 위 예시에서 특정 필드를 초기화하지 않으면, 해당 필드는 기본값인 0으로 설정됩니다.
사용자1 := 사용자{
이름: "모히트",
나이: 24,
}
// 출력 - { 모히트 24 0.0 }
new 키워드를 사용하여 구조체를 만드는 또 다른 방법이 있습니다. 다음 섹션에서 사용법을 살펴보겠습니다.
구조체 필드에 접근
구조체를 생성하고 초기화하는 방법을 배웠으니, 이제 구조체의 필드에 접근하는 방법을 알아볼 차례입니다. Go에서는 도트(.) 연산자를 사용하여 구조체 필드에 접근합니다. 이전 예시에서 이름과 나이 필드에 접근하여 출력해 보겠습니다.
package main
import (
"fmt"
)
type 사용자 struct {
이름 string
나이 int
잔고 float32
}
func main() {
// 필드 이름을 사용하여 초기화
사용자 := 사용자{
이름: "모히트",
나이: 24,
잔고: 100.0,
}
fmt.Println(사용자.이름)
fmt.Println(사용자.나이)
fmt.Println(사용자.잔고)
}
구조체의 필드에 접근하려면 구조체_이름.필드_이름 형식을 사용합니다. 위 코드의 출력 결과는 다음과 같습니다.
모히트 24 100
앞서 언급했듯이 new 키워드를 사용하여 구조체를 생성할 수도 있습니다. 다음은 그 예입니다.
사용자 := new(사용자)
사용자.이름 = "모히트"
사용자.나이 = 24
사용자.잔고 = 100.0
fmt.Println(사용자)
// 출력 - &{모히트 24 100}
new 키워드는 초기화된 구조체에 대한 포인터를 반환합니다. Go에서는 포인터를 명시적으로 역참조할 필요가 없지만, fmt.Println(*사용자)는 동일한 결과를 출력합니다.
중첩 구조체
Go의 구조체는 다른 사용자 정의 타입도 포함할 수 있습니다. 즉, 구조체 안에 다른 구조체를 중첩하여 사용할 수 있습니다.
package main
import (
"fmt"
)
type 사용자 struct {
이름 string
나이 int
잔고 float32
직책정보 직책정보
}
type 직책정보 struct {
직위 string
팀 string
}
func main() {
모히트직책정보 := 직책정보{
직위: "소프트웨어 엔지니어",
팀: "수송",
}
사용자 := 사용자{
이름: "모히트",
나이: 24,
잔고: 100.0,
직책정보: 모히트직책정보,
}
fmt.Println(사용자)
}
위 코드에서 사용자 구조체는 직책정보 구조체를 필드로 포함합니다. 출력 결과는 다음과 같습니다.
{모히트 24 100 {소프트웨어 엔지니어 수송}}
직책정보에 접근하려면 도트 연산자를 사용하여 접근할 수 있습니다.
사용자.직책정보.직위
구조체 동등성 비교
두 구조체는 포함된 모든 필드의 값이 동일할 때만 동등합니다. 하지만 맵(map)과 같은 특정 데이터 타입은 직접 비교할 수 없습니다. 구조체 동등성 비교의 예를 살펴보겠습니다.
package main
import (
"fmt"
)
type 사용자 struct {
이름 string
나이 int
잔고 float32
}
func main() {
사용자1 := 사용자{
이름: "모히트",
나이: 24,
잔고: 100.0,
}
사용자2 := 사용자{
이름: "모히트",
나이: 24,
잔고: 100.0,
}
사용자3 := 사용자{
이름: "니디",
나이: 21,
잔고: 1000.0,
}
if 사용자1 == 사용자2 {
fmt.Println("사용자1과 사용자2는 같습니다.")
} else {
fmt.Println("사용자1과 사용자2는 같지 않습니다.")
}
if 사용자1 == 사용자3 {
fmt.Println("사용자1과 사용자3는 같습니다.")
} else {
fmt.Println("사용자1과 사용자3는 같지 않습니다.")
}
}
값이 0인 빈 구조체는 서로 동일한 것으로 간주됩니다. 필드의 순서는 중요하지 않으며, 각 필드는 동등성 비교를 위해 모두 일치해야 합니다. 위 코드의 출력 결과는 다음과 같습니다.
사용자1과 사용자2는 같습니다. 사용자1과 사용자3는 같지 않습니다.
결론
축하합니다!
이제 Go 언어에서 구조체를 사용할 준비가 되었습니다. 구조체의 선언, 초기화, 필드 접근과 같은 기본적인 내용을 모두 다루었습니다. 또한 구조체 동등성 비교와 중첩 구조체 사용 방법도 살펴보았습니다. 다음은 구조체에 대해 더 자세히 알아볼 수 있는 추가 자료입니다.
구조체에 대해 더 많은 것을 배울 수 있지만, 지금 이 정도면 좋은 시작입니다. 새로운 것을 배우셨기를 바랍니다!
계속 탐구하고 학습하세요!