doujianzhi3358 2015-10-14 22:25
浏览 60
已采纳

使用反射从地图填充结构

I have a map of this kind type Store map[string]string

From this map, i would like to fill a struct. The goal is, for each field of the struct, find the key that match the field name, take the value, and based on the type of the struct field, convert the value to the proper struct field type and set it.

Basically the map will contains integers, booleans, strings and durations as strings so the convestion should be simply strconv.atoi(), time.parseDuration() ...

Also, i would like to use the structs tags to specify the name of the key in the map, because the struct field will be likely camelCase, while the keys in the map will be like this "example_key"

Any idea of how doing this. I have read about golang reflection but it is still opaque for me. I would just need an explanation to approach the problem, and then i think i can handle the implementation by my own.

Thanks

  • 写回答

1条回答 默认 最新

  • doufen1933 2015-10-14 23:15
    关注

    To avoid some extended discussion in comments I'm just going to make an answer explaining the two approaches I would choose from. Generally speaking, I would avoid the reflective method. There are cases where it is called for but most of the time the more verbose, literal, simple code will be better, even if it's a few more lines and there is some overlap between what the methods do.

    So, starting with the simple example. Suppose you got 3 types, GroceryStore, ComputerStore, and CornerStore. In whatever package each type is defined in, it is fairly common to define some constructor like methods (they're not technically constructors, just package scoped methods that instantiate a type and return it but same purpose). So an example would be;

    func NewComputerStore(store Store) *ComputerStore {
          return &ComputerStore{
                Name: store["Name"],
                Location: store["Location"],
                //ect
          }
    }
    

    Of course the example above is completely unsafe. In reality you need to use the v, ok := myMape["key"] syntax and then assign if ok and do whatever if not (probably some combination of assign default value, log error, and throw error).

    Now if you want a generalized method... It typically look something more like this (note this is untested and is more pseudo code than a working example);

    func (s *Store) ConvertToObject(obj interface{}) error {
        val := reflect.ValueOf(obj)
        for i := 0; i < val.NumField(); i++ {
            switch v := val.Field(i).(type) {
            case int64:
                val.Field(i).SetInt(strconv.Atoi(s[val.Field(i).Name]))
            }
        }
    }
    

    So the basic idea of the code above is this. You're starting with a store map. The caller knows what type that map is supposed to be. They call this method passing a new instance of that type. In the method we don't really care what the type is, we care what the type of it's fields are. So I iterate all the fields on the object passed in. Each field is put through the type switch (since I'll need a string to X conversion for every type that is present in the structs this method should work with, or at least a decent base case), in the case for each type you can do assignment using the field name to look up it's value in the Store map and converting from string to X.

    Hope that makes sense. I can follow up if it doesn't really clarify the approach. Remember the code above is not intended to run. Also, I've ignored all error handling which you will need lots of to make a generalized function work (what to do if conversion fails? What if type isn't recognized? What about all the other possible errors that won't be common place?).

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
  • ¥500 火焰左右视图、视差(基于双目相机)
  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统