মানচিত্রে কাঠামোতে রূপান্তর করা হচ্ছে


95

আমি গো তে একটি জেনেরিক পদ্ধতি তৈরি করার চেষ্টা করছি যা এ structথেকে একটি ব্যবহার করে ডেটা পূরণ করবে 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 ব্যবহার করে করা যেতে পারে; এটি করার আরও কার্যকর উপায় আছে?


4
মধ্যস্থতাকারী হিসাবে JSON ব্যবহার করা যাহাই হউক না কেন প্রতিবিম্ব ব্যবহার করবে .. ধরে নিই encoding/jsonযে আপনি মধ্যবর্তী পদক্ষেপটি করতে stdlib প্যাকেজটি ব্যবহার করছেন? .. আপনি কি এই উদাহরণটি ব্যবহার করতে পারেন এমন একটি মানচিত্র এবং উদাহরণ কাঠামো দিতে পারেন?
সাইমন হোয়াইটহেড

হ্যাঁ, এ কারণেই আমি জেএসএনকে এড়াতে চাইছি। মনে হচ্ছে সেখানে আশা করা যায় এমন আরও কার্যকর পদ্ধতি যা আমি জানিনা।
tgrosinger

আপনি একটি উদাহরণ ব্যবহারের ক্ষেত্রে দিতে পারেন? যেমন রয়েছে - কিছু সিউডোকোড দেখান যা দেখায় যে এই পদ্ধতিটি কী করবে?
সাইমন হোয়াইটহেড

মিমি ... unsafeপ্যাকেজটি নিয়ে কোনও উপায় থাকতে পারে .. তবে আমি এটি চেষ্টা করার সাহস পাই না। এর বাইরে .. প্রতিবিম্বটি আবশ্যক, যেমন আপনাকে কোনও ধরণের সাথে সম্পর্কিত মেটাডেটাটির বৈশিষ্ট্যগুলিতে ডেটা স্থাপনের জন্য কোয়েরি করতে সক্ষম হতে হবে। এটি json.Marshal+ json.Decodeকলগুলিতে মোড়ানো মোটামুটি সোজা হবে but তবে এটি প্রতিবিম্বের দ্বিগুণ।
সাইমন হোয়াইটহেড

আমি প্রতিবিম্ব সম্পর্কে আমার মন্তব্য সরিয়েছি। আমি যতটা সম্ভব দক্ষতার সাথে এটি করতে আরও আগ্রহী। এর অর্থ যদি প্রতিচ্ছবি ব্যবহার করা হয় তবে তা ঠিক আছে।
tgrosinger

উত্তর:


114

সবচেয়ে সহজ উপায় হ'ল https://github.com/mitchellh/mapst কাঠামো ব্যবহার করা

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)
}

4
ধন্যবাদ. আমি কিছুটা পরিবর্তিত সংস্করণ ব্যবহার করছি। play.golang.org/p/_JuMm6HMnU
tgrosinger

আমি আমার সমস্ত বিভিন্ন স্ট্রাক্টে ফিল স্ট্রাক্ট আচরণ চাই এবং প্রত্যেকটির জন্য কোনও সংজ্ঞা দিতে হবে না func (s MyStr...) FillStruct ...। বেস স্ট্রাক্টের জন্য ফিল স্ট্রাক্টকে সংজ্ঞায়িত করা কি আমার অন্যান্য স্ট্রাক্টের সেই আচরণের 'উত্তরাধিকারী' থাকা সম্ভব? উপরের দৃষ্টান্তে এটি সম্ভব নয় যেহেতু কেবলমাত্র বেস স্ট্রাক্ট ... এই ক্ষেত্রে "মাই স্ট্রাক্ট" এর আসলে ক্ষেত্রগুলি পুনরাবৃত্তি হবে
স্টার্টআপগুই

আমি আপনাকে বোঝাতে চাইছি এটির মতো কোনও কিছুতে এটি কোনও কাঠামোর
ডেভ

মাইস্ট্রাক্টে ট্যাগগুলি বাস্তবায়ন করা সম্ভব?
ভিসট্রোল্লা

4
@ অভিষেক অবশ্যই একটি পারফরম্যান্স পেনাল্টি রয়েছে যা আপনি প্রথমে পাঠ্যে মার্শালিংয়ের জন্য অর্থ প্রদান করবেন এবং তারপরে নিরবচ্ছিন্নকরণের জন্য pay যে পদ্ধতির এছাড়াও অবশ্যই সহজ। এটি একটি বাণিজ্য, এবং সাধারণত আমি সহজ সমাধান সঙ্গে যেতে হবে। আমি এই সমাধানটির সাথে উত্তর দিয়েছি কারণ প্রশ্নটি বলেছিল "আমি জানি জেএসওএনকে মধ্যস্থতাকারী হিসাবে ব্যবহার করে এটি করা যেতে পারে; এটি করার আরও একটি আরও কার্যকর উপায় আছে কি?"। এই সমাধানটি আরও কার্যকর হবে, JSON সমাধানটি সাধারণত কার্যকর করা এবং এর পক্ষে যুক্তিযুক্ত হওয়া সহজ হবে।
ডেভ

74

হাশিকর্পের https://github.com/mitchellh/mapstruct গ্রন্থাগারটি বাক্সের বাইরে এটি করেছে:

import "github.com/mitchellh/mapstructure"

mapstructure.Decode(myData, &result)

দ্বিতীয় resultপ্যারামিটারটির কাঠামোর ঠিকানা হতে হবে।


যদি মানচিত্র কীটি থাকে user_nameএবং স্ট্রাক্ট ফাইল হয় তবে UserNameকী হবে ?
নিকোলাস জেলা 23'18

4
@ নিকোলাস জেলা এটি ট্যাগটি সহ Godoc.org/github.com/mitchellh/mapstruct#ex-Decode--
প্রাচীরের সার্কিট

মানচিত্রের কী যদি _id হয় এবং মানচিত্রের নাম আইডি হয় তবে এটি এটিকে ডিকোড করবে না।
রবিশঙ্কর

27
  • এটি করার সহজ উপায় হ'ল encoding/jsonপ্যাকেজ ব্যবহার করা

যেমন উদাহরণস্বরূপ:

package main
import (
    "fmt"
    "encoding/json"
)

type MyAddress struct {
    House string
    School string
}
type Student struct {
    Id int64
    Name string
    Scores float32
    Address MyAddress
    Labels []string
}

func Test() {

    dict := make(map[string]interface{})
    dict["id"] = 201902181425       // int
    dict["name"] = "jackytse"       // string
    dict["scores"] = 123.456        // float
    dict["address"] = map[string]string{"house":"my house", "school":"my school"}   // map
    dict["labels"] = []string{"aries", "warmhearted", "frank"}      // slice

    jsonbody, err := json.Marshal(dict)
    if err != nil {
        // do error check
        fmt.Println(err)
        return
    }

    student := Student{}
    if err := json.Unmarshal(jsonbody, &student); err != nil {
        // do error check
        fmt.Println(err)
        return
    }

    fmt.Printf("%#v\n", student)
}

func main() {
    Test()
}

4
ধন্যবাদ @ জ্যাকাইটস। এটি আসলে এটি করার সর্বোত্তম উপায় !! মানচিত্রের কাঠামো প্রায়শই কোনও ইন্টারফেসের মধ্যে নেস্টেড মানচিত্রের সাথে কাজ করে না। সুতরাং এটি মানচিত্রের স্ট্রিং ইন্টারফেসটিকে আরও ভালভাবে বিবেচনা করুন এবং এটিকে জসন হিসাবে হ্যান্ডেল করুন।
গিলস এসোসকি

উপরের স্নিপেটের জন্য খেলার মাঠের লিঙ্কটি যান: play.golang.org/p/JAKxETAbsnT
জুনাইদ

13

আপনি এটি করতে পারেন ... এটি কিছুটা কুৎসিত হতে পারে এবং আপনাকে ম্যাপিংয়ের ধরণের ক্ষেত্রে কিছু পরীক্ষা এবং ত্রুটির মুখোমুখি হতে হবে .. তবে এটির মূল বক্তব্য এখানে:

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


4
এটি শূন্য মানগুলিতে আতঙ্কিত হবে বলে মনে হচ্ছে:reflect: call of reflect.Value.Set on zero Value
জেমস টেলর

পছন্দ করুন আমার উত্তর ধরে নিচ্ছে আপনি ঠিক কী ক্ষেত্রগুলি ম্যাপ করছেন তা জানেন know যদি আপনি আরও ত্রুটি পরিচালনার সাথে একইরকম উত্তর পেয়ে থাকেন (আপনি যে ত্রুটিটি অনুভব করছেন তা সহ) তবে আমি এর পরিবর্তে ড্যাভসকে উত্তর দেওয়ার পরামর্শ দেব।
সাইমন হোয়াইটহেড

2

আমি ডেভের উত্তরটি অভিযোজিত করেছি এবং একটি পুনরাবৃত্ত বৈশিষ্ট্য যুক্ত করছি। আমি এখনও আরও ব্যবহারকারী বান্ধব সংস্করণে কাজ করছি। উদাহরণস্বরূপ, মানচিত্রে একটি সংখ্যা স্ট্রিং স্ট্রাক্ট ইন ইন রূপান্তর করতে সক্ষম হওয়া উচিত।

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)
}

1

দুটি পদক্ষেপ রয়েছে:

  1. ইন্টারফেসটি JSON বাইটে রূপান্তর করুন
  2. JSON বাইটকে কাঠামোতে রূপান্তর করুন

নীচে একটি উদাহরণ দেওয়া হল:

dbByte, _ := json.Marshal(dbContent)
_ = json.Unmarshal(dbByte, &MyStruct)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.