반응형
맵을 구조체로 변환
.NET Framework에서 struct
데이터를 사용하여 채울 Go에서 일반 메서드를 만들려고 합니다 map[string]interface{}
. 예를 들어, 메소드 서명 및 사용법은 다음과 같습니다.
func FillStruct(data map[string]interface{}, result interface{}) {
...
}
type MyStruct struct {
Name string
Age int64
}
myData := make(map[string]interface{})
myData["Name"] = "Tony"
myData["Age"] = 23
result := &MyStruct{}
FillStruct(myData, result)
// result now has Name set to "Tony" and Age set to 23
JSON을 중개자로 사용하여이 작업을 수행 할 수 있다는 것을 알고 있습니다. 이 작업을 수행하는 또 다른 더 효율적인 방법이 있습니까?
가장 간단한 방법은 https://github.com/mitchellh/mapstructure 를 사용하는 것입니다.
import "github.com/mitchellh/mapstructure"
mapstructure.Decode(myData, &result)
직접하고 싶다면 다음과 같이 할 수 있습니다.
http://play.golang.org/p/tN8mxT_V9h
func SetField(obj interface{}, name string, value interface{}) error {
structValue := reflect.ValueOf(obj).Elem()
structFieldValue := structValue.FieldByName(name)
if !structFieldValue.IsValid() {
return fmt.Errorf("No such field: %s in obj", name)
}
if !structFieldValue.CanSet() {
return fmt.Errorf("Cannot set %s field value", name)
}
structFieldType := structFieldValue.Type()
val := reflect.ValueOf(value)
if structFieldType != val.Type() {
return errors.New("Provided value type didn't match obj field type")
}
structFieldValue.Set(val)
return nil
}
type MyStruct struct {
Name string
Age int64
}
func (s *MyStruct) FillStruct(m map[string]interface{}) error {
for k, v := range m {
err := SetField(s, k, v)
if err != nil {
return err
}
}
return nil
}
func main() {
myData := make(map[string]interface{})
myData["Name"] = "Tony"
myData["Age"] = int64(23)
result := &MyStruct{}
err := result.FillStruct(myData)
if err != nil {
fmt.Println(err)
}
fmt.Println(result)
}
Hashicorp의 https://github.com/mitchellh/mapstructure 라이브러리는이 작업을 즉시 수행합니다.
import "github.com/mitchellh/mapstructure"
mapstructure.Decode(myData, &result)
두 번째 result
매개 변수는 구조체의 주소 여야합니다.
당신은 그것을 할 수 있습니다 ... 그것은 약간 추악해질 수 있으며 매핑 유형 측면에서 시행 착오에 직면하게 될 것입니다 .. 그러나 여기에 기본적인 요점이 있습니다.
func FillStruct(data map[string]interface{}, result interface{}) {
t := reflect.ValueOf(result).Elem()
for k, v := range data {
val := t.FieldByName(k)
val.Set(reflect.ValueOf(v))
}
}
작업 샘플 : http://play.golang.org/p/PYHz63sbvL
dave의 대답을 수정하고 재귀 기능을 추가합니다. 나는 여전히 더 사용자 친화적 인 버전을 작업 중입니다. 예를 들어 맵의 숫자 문자열은 구조체에서 int로 변환 할 수 있어야합니다.
package main
import (
"fmt"
"reflect"
)
func SetField(obj interface{}, name string, value interface{}) error {
structValue := reflect.ValueOf(obj).Elem()
fieldVal := structValue.FieldByName(name)
if !fieldVal.IsValid() {
return fmt.Errorf("No such field: %s in obj", name)
}
if !fieldVal.CanSet() {
return fmt.Errorf("Cannot set %s field value", name)
}
val := reflect.ValueOf(value)
if fieldVal.Type() != val.Type() {
if m,ok := value.(map[string]interface{}); ok {
// if field value is struct
if fieldVal.Kind() == reflect.Struct {
return FillStruct(m, fieldVal.Addr().Interface())
}
// if field value is a pointer to struct
if fieldVal.Kind()==reflect.Ptr && fieldVal.Type().Elem().Kind() == reflect.Struct {
if fieldVal.IsNil() {
fieldVal.Set(reflect.New(fieldVal.Type().Elem()))
}
// fmt.Printf("recursive: %v %v\n", m,fieldVal.Interface())
return FillStruct(m, fieldVal.Interface())
}
}
return fmt.Errorf("Provided value type didn't match obj field type")
}
fieldVal.Set(val)
return nil
}
func FillStruct(m map[string]interface{}, s interface{}) error {
for k, v := range m {
err := SetField(s, k, v)
if err != nil {
return err
}
}
return nil
}
type OtherStruct struct {
Name string
Age int64
}
type MyStruct struct {
Name string
Age int64
OtherStruct *OtherStruct
}
func main() {
myData := make(map[string]interface{})
myData["Name"] = "Tony"
myData["Age"] = int64(23)
OtherStruct := make(map[string]interface{})
myData["OtherStruct"] = OtherStruct
OtherStruct["Name"] = "roxma"
OtherStruct["Age"] = int64(23)
result := &MyStruct{}
err := FillStruct(myData,result)
fmt.Println(err)
fmt.Printf("%v %v\n",result,result.OtherStruct)
}
- 이를 수행하는 가장 간단한 방법은
encoding/json
패키지를 사용하는 것입니다.
예를 들면 :
package main
import (
"fmt"
"encoding/json"
)
func Test() {
dict := make(map[string]interface{})
dict["id"] = 201902181425
dict["name"] = "jackytse"
dict["scores"] = 123.456
dict["address"] = map[string]string{"home":"address1", "company":"address2"}
dict["labels"] = []string{"aries", "warmhearted", "frank"}
jsonbody, err := json.Marshal(dict)
if err != nil {
// do error check
fmt.Println(err)
return
}
type AddressDefine struct {
Home string
Company string
}
type Student struct {
Id int64
Name string
Scores float32
Address AddressDefine
Labels []string
}
people := Student{}
if err := json.Unmarshal(jsonbody, &people); err != nil {
// do error check
fmt.Println(err)
}
fmt.Printf("%#v\n", people)
}
func main() {
Test()
}
참고 URL : https://stackoverflow.com/questions/26744873/converting-map-to-struct
반응형
'programing tip' 카테고리의 다른 글
TypeError : 데이터를 지수 적으로 맞추려고 시도하는 동안 길이 1 배열 만 Python 스칼라로 변환 될 수 있습니다. (0) | 2020.10.29 |
---|---|
브레이크 (루프 / 스위치)에 응답하는 내부 구조에서 외부 루프를 끊는 방법 (0) | 2020.10.29 |
Angular + Material-데이터 소스를 새로 고치는 방법 (매트 테이블) (0) | 2020.10.29 |
ASP.NET MVC Ajax.ActionLink with Image (0) | 2020.10.29 |
안드로이드 다운로드 바이너리 파일 문제 (0) | 2020.10.29 |