프로그래밍/Go

[Go] 구조체 (Struct)

프로그래민구찌 2024. 11. 22. 20:28

Go 언어의 구조체 (Struct)

- 구조체는 Go언어에서 데이터를 묶어서 표현하기 위해 사용하는 사용자 정의 타입

- 여러 필드를 하나로 묶어 관련된 데이터를 관리

- 객체지향 언어의 클래스와 비슷하지만 메서드와 상속 기능은 없으며, 필드만을 정의


특징

1. 데이터 묶음

- 서로 다른 데이터 타입의 필드를 하나로 묶어서 사용할 수 있음.

2. 타입 정의

- 구조체는 새 데이터 타입을 정의하는 데 사용됨.

3. 메모리

- 값 타입으로 동작하지만, 포인터로 참조하여 동작할 수도 있음.

4. 내장 필드 및 사용자 정의 필드 사용 가능

- 필드에 기본값 없음(명시적으로 초기화 해야함.)


구조체 정의와 사용법

1. 기본 구조체 정의

package main

import "fmt"

// 구조체 정의
type Person struct {
	Name string
	Age  int
	City string
}

func main() {
	// 구조체 인스턴스 생성 및 초기화
	p1 := Person{Name: "Alice", Age: 30, City: "Seoul"}
	p2 := Person{"Bob", 25, "Busan"} // 필드 순서대로 초기화

	// 값 출력
	fmt.Println("Person 1:", p1)
	fmt.Println("Person 2:", p2)
}

출력결과
Person 1: {Alice 30 Seoul}
Person 2: {Bob 25 Busan}

2. 구조체의 필드 접근 및 수정

package main

import "fmt"

type Person struct {
	Name string
	Age  int
	City string
}

func main() {
	// 구조체 초기화
	p := Person{Name: "Charlie", Age: 28, City: "Incheon"}

	// 필드 접근
	fmt.Println("Name:", p.Name)
	fmt.Println("Age:", p.Age)
	fmt.Println("City:", p.City)

	// 필드 값 수정
	p.Age = 29
	fmt.Println("Updated Age:", p.Age)
}

출력결과
Name: Charlie
Age: 28
City: Incheon
Updated Age: 29

3. 포인터를 사용한 구조체 수정

package main

import "fmt"

type Account struct {
	Number  string
	Balance float64
}

func UpdateBalance(a *Account, amount float64) {
	a.Balance += amount // 포인터를 통해 원본 수정
}

func main() {
	acc := Account{Number: "123-456", Balance: 1000.0}

	// 함수 호출 전
	fmt.Println("Before:", acc.Balance)

	// 함수 호출
	UpdateBalance(&acc, 500)

	// 함수 호출 후
	fmt.Println("After:", acc.Balance)
}

출력결과
Before: 1000
After: 1500

4. 메서드를 사용하는 구조체

- 구조체와 함께 메서드를 정의하면 객체지향적인 코드 작성이 가능

package main

import "fmt"

type Rectangle struct {
	Width, Height float64
}

// 구조체 메서드 정의
func (r Rectangle) Area() float64 {
	return r.Width * r.Height
}

func (r Rectangle) Perimeter() float64 {
	return 2 * (r.Width + r.Height)
}

func main() {
	rect := Rectangle{Width: 10, Height: 5}

	// 메서드 호출
	fmt.Println("Area:", rect.Area())
	fmt.Println("Perimeter:", rect.Perimeter())
}

출력결과
Area: 50
Perimeter: 30

5. 구조체 임베디드 패턴

- 다른 관점으로 메소드를 재사용하는 장점 제공

- 상속을 허용하지 않는 Go언어에서 메소드 상속 활용을 위한 패턴

package main

import "fmt"

type Employee struct {
	name string
	salary float64
	bonus float64
}

func (e Employee) Calculate() float64 {
	return e.salary + e.bonus
}

type Executives struct {
	Employee // is a 관계
	specialBonus float64
}

func main() {
	// 구조체 임베디드 패턴
	// 다른 관점으로 메소드를 재사용하는 장점 제공
	// 상속을 허용하지 않는 Go 언어에서 메소드 상속 활용을 위한 패턴
 
	// 직원
	ep1 := Employee{"kim", 2000000, 150000}
	ep2 := Employee{"park", 1500000, 200000}

	// 임원
	ex := Executives {
		Employee{"lee", 5000000, 1000000},
		1000000, // specialBonus
	}

	fmt.Println("ex1 : ", int(ep1.Calculate()))
	fmt.Println("ex1 : ", int(ep2.Calculate()))

	// Employee 구조체 통해서 메소드 호출
	fmt.Println("ex2 : ",  int(ex.Calculate() + ex.specialBonus))
 
}

출력결과
ex1 :  2150000
ex1 :  1700000
ex2 :  7000000

6. 구조체 임베디드 메소드 오버라이딩 패턴

// 구조체 심화(5)

package main

import "fmt"

type Employee struct {
	name string
	salary float64
	bonus float64
}

func (e Employee) Calculate() float64 {
	return e.salary + e.bonus
}

func (e Executives) Calculate() float64 {
	return e.salary + e.bonus + e.specialBonus
}

type Executives struct {
	Employee // is a 관계
	specialBonus float64
}

func main() { 
	// 직원
	ep1 := Employee{"kim", 2000000, 150000}
	ep2 := Employee{"park", 1500000, 200000}

	// 임원
	ex := Executives {
		Employee{"lee", 5000000, 1000000},
		1000000, // specialBonus
	}

	fmt.Println("ex1 : ", int(ep1.Calculate()))
	fmt.Println("ex1 : ", int(ep2.Calculate()))

	// Employee 구조체 통해서 메소드 호출  
	fmt.Println("ex2 : ",  int(ex.Calculate())) 

}

출력결과
ex1 :  2150000
ex1 :  1700000
ex2 :  7000000

요약

- 구조체는 데이터의 묶음으로 관련 데이터를 하나로 관리.

- 초기화 시 필드를 명시적으로 작성하거나, 필드 순서대로 값을 설정 가능.

- 포인터를 통해 원본 데이터 수정 가능.

- 메서드를 사용하여 구조체와 관련된 동작을 정의 가능.