Go 언어 struct – 업무에 사용하는 Go 언어 11

Go 언어 struct(구조체)는 다른 언어에서 기본적으로 제공하는 struct와 비슷합니다.
다만, Go 언어에는 OOP(객체 지향 프로그래밍)에서 흔히 사용하는 class가 존재하지 않습니다.
Go 언어 struct가 class와 유사한 역할을 하는데, 상속과 같은 기능을 제공하지는 않고, interface를 통해 여러가지 기능을 제공합니다.
Struct를 활용하여 간단한 데이터부터 복잡한 데이터 모델링까지 가능하게 해주기 때문에 꼭 살펴보고 넘어가야 합니다.
본 글에서는 struct의 기본 개념부터 사용 방법까지 살펴보도록 하겠습니다.

업무에 사용하는 Go 언어 썸네일

실제로 필자가 웹 관련 업무를 하거나 데이터 관련 업무를 할 때 꼭 사용하게 되고,
피할 수 없는 것이 struct라고 생각한다.

타 언어와 다른 특징으로 class를 제공하지 않기 때문에
“미리 어떠한 행위와 함께 자료의 구조를 정해둔다”와 같은 행위를 소스 코드에
구현해야 할 때 무조건적으로 사용하게 되는 것 같다.

[ 프로젝트 참고 ]

함께 만든 프로젝트에 struct.go 파일을 만들어서 진행했습니다.

struct 선언 및 초기화

struct는 기본적으로 새로운 데이터 타입을 만들기 위해 사용한다고 생각하면 편합니다.
Go 언어 struct 또한 다양한 데이터 타입을 사용하여 여러 필드를 포함 시킬 수 있습니다.
선언을 하기 위해서는 사용자 정의 데이터 타입을 정의했던 것과 동일하게 type 키워드를 통해 정의하면 됩니다.

struct 정의

Go
type Person struct {
  Name string
  Age  int
}

struct 예시로 꼭 나오는 코드랍니다.
Person이라는 타입을 정의한 것으로 이 struct에는 Name와 Age라는 두 개의 필드를 포함시켰습니다.
적절하게 Name에는 string 타입을, Age에는 int 타입을 지정해주었습니다.

struct 초기화

새로운 데이터 타입을 만들었으면 정의했으면 이제 사용을 해봐야겠습니다.
Go 언어에는 어떠한 데이터 타입을 사용하기 위해서 초기화를 해주는 습관이 필요하답니다.
(Go 언어에서 struct가 OOP에서 사용하는 역
struct를 초기화하는 방법에 여러 가지가 있는데 다음 중 상황에 적절한 방법을 사용하면 됩니다.

기본 초기화

Go
var p Person

모든 필드를 각 타입의 zero value로 초기화하여 Person 타입의 변수 p를 생성하는 예시입니다.

필드를 “명시”한 초기화

Go
p := Person{Name: "Alice", Age: 25}

앞에서 정의한 Person 데이터 타입의 Name, Age 필드를 명시하여 값을 지정하여 초기화하는 예시입니다.

필드를 “생략”한 초기화

Go
p := Person{"Alice", 25}

앞에서 정의한 Person 데이터 타입의 Name, Age 필드에 대하여 순서대로 값을 지정하여 초기화하는 예시입니다.
정의할 때와 같은 순서로 값을 지정하는 것이 중요합니다.

new 키워드를 사용한 초기화

Go
p := new(Person)

Go 언어의 내장함수 new를 사용하여 초기화 할 수도 있습니다.
이 방법은 기본 초기화 방법과 비슷하게 모든 필드의 값을 zero value로 초기화하는 것은 동일하지만,
초기화된 데이터에 대한 포인터를 반환한답니다.
( 구조체 Person 타입의 객체에 대한 포인터 변수 p가 된다는 의미 )

struct 필드 접근

Go 언어 struct 필드 접근은 . (dot) 연산자를 사용하여 접근하게 됩니다.
다음 코드를 참고하여 직접 사용해보도록 합시다.

Go
package main

import "fmt"

type Person struct {
	Name string
	Age  int
}

func main() {
	p1 := Person{Name: "Alice", Age: 25}
	fmt.Println(p1.Name)
	p1.Age = 26

	p2 := new(Person)
	p2.Name = "Bob"
	p2.Age = 27

	fmt.Println(p2)
}

직접 사용을 해보시다 보면 의문을 가지실 수도 있습니다.
15번~17번 줄을 보시면 포인터를 반환한다고 했는데 ->를 사용하는 등 다른 방법을 시도하지 않습니다.
그 이유는 객체의 포인터에 대해서도 필드 접근을 할 때 . (dot) 연산자를 사용합니다.
Go 언어에서는 내부적으로 메모리 주소에 해당하는 데이터의 필드에 접근하기 때문에 가능합니다.
따라서, Go 언어에서는 역참조를 명시할 필요가 없다가 공식적인 표현이 된답니다.

추가 : struct와 json

Go언어로 json 형태의 데이터를 다룰 때 많이 사용되는 패턴을 추가로 소개하도록 하겠습니다.
encoding/json 패키지를 사용하여 데이터를 struct로(혹은 json으로) 변환할 수 있답니다.

struct to json

Go
import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

p := Person{Name: "Alice", Age: 25}
jsonData, _ := json.Marshal(p)
fmt.Println(string(jsonData)) // {"name":"Alice","age":25}

json to struct

Go
jsonStr := `{"name":"Alice","age":25}`
var p Person
json.Unmarshal([]byte(jsonStr), &p)
fmt.Println(p) // {Alice 25}

Take it home

  • Go 언어 struct는 새로운 데이터 구조를 정의하는 도구이다.
  • Go 언어에서는 struct를 이용하여 OOP를 하게 된다.
  • Go 언어에서는 객체에 대한 포인터에 대해서도 역참조에 대한 명시를 하지 않아도 된다.

다음 글에서 알아볼 내용

Go 언어 method