Golang 구조체의 필드를 동적으로 다루는 법

박재훈·2022년 10월 22일
0

GO

목록 보기
2/19

자바스크립트에서는 object 필드에 동적으로 접근하기가 매우 간단하다.

const person = {
	gretting: 'hello',
    name: 'John Doe',
}

// 통상적인 방법
console.log(person.gretting);
// 동적인 접근법
console.log(person['gretting']);

그래서 자바스크립트를 이용해서 개발할 때에는 이러한 방식을 많이 이용했었는데, Go로 개발을 시작하고나서는 이 방식을 쓸 수 없어서 한동안 불편했었다.

그런데 reflect 패키지를 사용하면 동적으로 구조체 필드에 접근 가능하다.

먼저 위에서 사용한 것과 같이 Person이라는 구조체가 있다고 하고 그 객체를 만들었을 때,

type Person struct {
	Gretting string
    Name     string
}

person := Person{
	Gretting: "hello",
    Name:     "John Doe",
}

먼저 코드는 위와 같이 된다.

그리고 위 person 객체에서 Gretting 필드를 동적으로 가져오고 싶다고 하면 다음과 같은 코드를 이용하면 된다.

reflect.Indirect(reflect.ValueOf(구조체변수)).FieldByName(필드명).String()

// example
field := "Name"
value := reflect.Indirect(reflect.ValueOf(person)).FieldByName(field).String()
fmt.Println(value) // John Doe

이런 식으로 따로 인터페이스를 이용하지 않고도 다이나믹한 프로그래밍이 가능하다.
또, 전체 필드 리스트를 가져오는 법은 다음과 같다.

e := reflect.ValueOf(&구조체{}).Elem()
fields := []string{} // 필드명들이 담길 배열
for i := 0; i < e.NumField(); i++ {
	columns = append(fields, e.Type().Field(i).Name)
}

// example
e := reflect.ValueOf(&Person{}).Elem()
fields := []string{}
for i := 0; i < e.NumField(); i++ {
	fields = append(fields, e.Type().Field(i).Name)
}
fmt.Println(fields) // ["Gretting", "Name"]

이 두 방식을 조합하면 전체 필드값을 출력하는 등의 방식이 가능하다.

type Person struct {
	Gretting string
	Name     string
}

func main() {
	e := reflect.ValueOf(&Person{}).Elem()
	fields := []string{}
	for i := 0; i < e.NumField(); i++ {
		fields = append(fields, e.Type().Field(i).Name)
	}

	person := Person{Gretting: "hello", Name: "John Doe"}
	for _, field := range fields {
		value := reflect.Indirect(reflect.ValueOf(person)).FieldByName(field).String()
		fmt.Printf("%v: %v\n", field, value)
	}
}
// 실행 결과
Gretting: hello
Name: John Doe

하지만 reflect 패키지를 자주 사용하는 것은 Go스럽지 않다고 한다.

profile
코딩 좋아합니다

0개의 댓글