구조체는 리스트에 비해서 명확하고 코드의 가독성을 높여주기에 애용하는 편이다.
또한 여러 타입의 변수를 하나에 묶어둘 수 있다는 것도 장점이다.

귀찮은 점은 list 나 array는 for문으로 대충 쭉 훑는게 가능한데 구조체는 그게 간단하지가 않다.

하지만 그렇다고 전체가 필요할 때 구조체의 필드명을 하나하나 말하고 있으면 코드가 길어지고 확장성이 떨어진다.

이번 Golang으로 하는 작업 중에 Field를 열거해 줄 일이 있었다.

Golang은 깐깐해 보이면서도 Interface라는 상당히 유연한 시스템을 가지고 있다. 먼저 다음의 코드를 살펴보자

package main

import (
	"fmt"
	"reflect"
)

type Person struct {
	Name string
	City string
	Age  int
}

func main() {
	s := Person{"EBeb", "Hoshimi", 17}
	v := reflect.ValueOf(s)
	type_of_fields := v.Type()
	for i := 0; i < v.NumField(); i++ {
		fmt.Printf(" %s : %v\n", type_of_fields.Field(i).Name, v.Field(i).Interface())
	}
}

출력

 Name : EBeb
 City : Hoshimi
 Age : 17

Program exited.

reflect에는 변수형을 다루는 여러가지 함수들이 있는 것 같다. 종종 보인다.

먼저 reflect.ValueOf 에 관한 설명이다.
Type은 이 구조체를 Type형으로 return해주는 역할을 한다. Field는 index상에 있는 Field의 값을 구조체에 담아준다.

즉 이 Field의 값이 뭐가 나올 지 모르기 때문에 여러 변수형들에 대한 구조체를 준비해서 적절한 곳에 대입한다.
Interface를 사용하여 여기서 실제 값을 그 타입에 맞게 반환시킨다.

공식문서 상에서 Type안의 .Field의 설명이다

// Field returns a struct type's i'th field.
// It panics if the type's Kind is not Struct.
// It panics if i is not in the range [0, NumField()).
Field(i int) StructField

그럼 Return하는 StructField는 무슨 구조일까

type StructField struct {
	// Name is the field name.
	Name string

	// PkgPath is the package path that qualifies a lower case (unexported)
	// field name. It is empty for upper case (exported) field names.
	// See https://golang.org/ref/spec#Uniqueness_of_identifiers
	PkgPath string

	Type      Type      // field type
	Tag       StructTag // field tag string
	Offset    uintptr   // offset within struct, in bytes
	Index     []int     // index sequence for Type.FieldByIndex
	Anonymous bool      // is an embedded field
}

음 Field에 대한 정보들을 가져올 수 있다. Name으로 그 Field의 이름이나 Type으로 그 Field의 타입을 가져올 수 있다.