从结构体映射中调用结构体。

huangapple go评论83阅读模式
英文:

Call struct from map of structs

问题

嗨,我正在尝试类似以下示例的东西。

作为一个PHP开发者(我知道!),这让我很困扰。我已经阅读了反射定律和其他资料,但这超出了我的理解范围。我使用的方法可能是错误的...希望有人能指点我正确的方向。

具体使用的目的是,版本01、02或03是来自外部参数的,基于此,我需要获取相应的结构体并用数据库值填充它。

package V01
type Struct1 struct{
    Field1 string
    Field2 string
}

type Struct2 struct{
    Field1 string
    Field2 string
}

---

package V02
type Struct1 struct{
    Field1 string
    Field2 string
    ExtraField1 string
}

type Struct2 struct{
    Field1 string
    Field2 string
    ExtraField2 string
    ExtraField3 string
}

---

var VStructs = map[string]map[string]interface{}{
    "01": map[string]interface{}{
        "Struct1": V01.Struct1{},
        "Struct2": V01.Struct2{},
    },
    "02": map[string]interface{}{
        "Struct1": V02.Struct1{},
        "Struct2": V02.Struct2{},
    }, 
    "03" : map[string]interface{}{
        "Struct1": V01.Struct1{},
        "Struct2": V02.Struct2{},
    }, 
}

---

// 获取结构体字段名等信息。
fmt.Printf("%+v\n", VStructs["01"]["Struct1"])

// 但是我无法访问任何字段,因为它是一个接口。
fmt.Println(VStructs["01"]["Struct1"].Field1) // 报错!

// 类型切换也不起作用,因为版本可能是可变的。
s := VStructs["01"]["Struct1"].Field1 
switch x := s.(type) {
case reflect.Struct: // 报错!reflect.Struct(类型reflect.Kind)不是一个类型
    fmt.Println("我是一个结构体")
default:
    fmt.Println("我不是一个结构体")
}

---

所以也许你可以向我展示一种适当的方法来做这个或者也许是一个返回正确结构体的包装函数...目前不清楚

希望这样清楚明了如果有需要我可以提供更多细节

<details>
<summary>英文:</summary>

Hi I am trying something like the following example. 

My background as a PHP Developer (I know!) is giving me a hard time on this.
I&#39;ve read the Laws of reflection and other sources, but this is over my head. The approach i am using is probably wrong... and hope someone can point me in the right direction. 

The use of this in a concrete way is that the version 01 or 02 or 03 is comming from an external Parameter, based on that, I need to get the appropriate struct and populate it with database values.

    package V01
    type Struct1 struct{
        Field1 string
        Field2 string
    }
    
    type Struct2 struct{
        Field1 string
        Field2 string
    }

---


    package V02
    type Struct1 struct{
        Field1 string
        Field2 string
        ExtraField1 string
    }
    
    type Struct2 struct{
        Field1 string
        Field2 string
        ExtraField2 string
        ExtraField3 string
    }

---

    var VStructs = map[string]map[string]interface{}{
    	&quot;01&quot;: map[string]interface{}{
    		&quot;Struct1&quot;: V01.Struct1{},
    		&quot;Struct2&quot;: V01.Struct2{},
    	},
    	&quot;02&quot;: map[string]interface{}{
    		&quot;Struct1&quot;: V02.Struct1{},
    		&quot;Struct2&quot;: V02.Struct2{},
    	}, 
        &quot;03&quot; : map[string]interface{}{
    		&quot;Struct1&quot;: V01.Struct1{},
    		&quot;Struct2&quot;: V02.Struct2{},
    	}, 
    }

---

     // I get the struct fieldnames and so on.
     fmt.Printf(&quot;%+v\n&quot;, VStructs[&quot;01&quot;][&quot;Struct1&quot;] ) 

     // I cannot access any of the fields though because it is an interface
     fmt.Println( VStructs[&quot;01&quot;][&quot;Struct1&quot;].Field1 ) // PANIC! 

     // Type Switching is not working either since the version can be variable.
     s := VStructs[&quot;01&quot;][&quot;Struct1&quot;].Field1 
	 switch x := s.(type) {
	 case reflect.Struct: // PANIC! reflect.Struct (type reflect.Kind) is not a type
		fmt.Println(&quot;I am an struct&quot;)
	 default:
		fmt.Println(&quot;I am an no struct&quot;)
	 }

---

So maybe can show me an appropriate way of doing this. Or maybe an wrapper function to return the right struct... no clue at this point. 

Hope it is clear, and will elaborate more if asked to.

</details>


# 答案1
**得分**: 0

你无法通过这种方式访问映射中的结构体因为可能没有结构体存在在你的示例中`VStructs["foo"]["bar"].Field1`会是什么呢你无法知道它是否真的是映射中的空结构体还是映射访问只是返回了该类型的空值相反你应该进行显式检查

```go
v, ok := VStructs["01"]["Struct1"]
if !ok {
    // 处理缺少结构体的情况。
}
// 检查类型断言也是一个好习惯。
s, ok := v.(V01.Struct1)
if !ok {
    // 处理 v 不是 V01.Struct1 的情况。
}
f = s.Field1
英文:

You cannot access the struct inside a map this way because there may be no struct. In your example, what would VStructs[&quot;foo&quot;][&quot;bar&quot;].Field1 be? You would have no way of knowing if it's really an empty struct in the map, or there is nothing and the map access just returned you an empty value for that type. What you should do instead is an explicit check:

v, ok := VStructs[&quot;01&quot;][&quot;Struct1&quot;]
if !ok {
// Handle the case of the missing struct.
}
// It is also a good practice to check type assertions.
s, ok := v.(V01.Struct1)
if !ok {
// Handle the case when v is not V01.Struct1.
}
f = s.Field1

答案2

得分: 0

好的,以下是翻译好的内容:

好的,由于问题可能与使用golang的方式存在冲突。

我编写了一个包来满足我的需求:

根据选择的版本(在URL或标头中,任何你喜欢的方式),我们检索到一个结构体的映射。现在我们可以选择我们需要的实际结构体,设置一些值,最后将其发送回屏幕或发送到数据库(在我的情况下是gorp)。

该包可以在这里找到:https://github.com/donseba/contractor/

英文:

Okay, since the question was probably in conflict with the way golang is used to work.

I have written an package to serve my needs :

> Based on the selected version (In the URL or the Header, whatever you like) we retrieve an map of structs. We now can select the actual struct we need, set some values and finally send it back to the screen OR send it over to the DB (In my case gorp).

The Package can be found here https://github.com/donseba/contractor/

huangapple
  • 本文由 发表于 2014年11月18日 19:34:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/26993340.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定