<p>A part of my program receives map of type <code>map[interface{}]interface{}</code> as input and it has to check for the presence of a certain value. Specifically, it has to confirm if the map contains a certain list and if the list contains a string called role1. In python, I'd do it like this,</p>
<pre><code>test = "some-string"
mylist = map.get("mylist", [])
return isinstance(mylist, (list, tuple,)) and test in mylist
</code></pre>
<p>... but with my extremely limited experience in Go, I've come up with this,</p>
<pre><code>test := "some-string"
mylist = inputMap["mylist"]
if reflect.TypeOf(mylist).Kind() == reflect.Slice {
for _, child := range mylist.([]interface{}) {
if reflect.TypeOf(child).Kind() == reflect.String {
if test == child {
return true
}
}
}
}
return false
</code></pre>
<p>I feel there must be a better way. What is the idiomatic way to solve this in Go?</p>
<p>Let's say I don't have control over the input and it'll always be of type <code>map[interface{}]interface{}</code>. Is there a way I can reliably convert/cast it into a custom type without using reflect?</p>
<hr/>**评论:**<br/><br/>neoasterisk: <pre><p>Since you mentioned that you are new to Go and it seems that you are trying to write Go code the way you write Python code, I would suggest you to watch Rob Pike's excellent talk "Go proverbs" especially the parts: <a href="https://youtu.be/PAAkCSZUG1c?t=7m35s" rel="nofollow">interface{} says nothing</a> and <a href="https://www.youtube.com/watch?v=PAAkCSZUG1c&feature=youtu.be&t=15m22s" rel="nofollow">Reflection is never clear</a>.</p></pre>lonahex: <pre><p>Thanks! </p></pre>the_jester: <pre><p>In general, the idiomatic answer is: don't. </p>
<p>If you can possibly help it you should pass around something more specific than map[interface{}]interface{}. The latter could be a single-member struct or an interface. Your interface could even be a one-method interface that supplies a method that encompasses your "some-string" test. Then just use that method on the interface to satisfy your test.</p>
<p>with a map[interface{}]MyMoreSpecificType you can just define your comparator as a typed method, and run it in your range function</p></pre>lonahex: <pre><p>The input to the program is completely out of my control. Think of it as any arbitrary JSON. It may contain <code>mylist</code> or may not. <code>mylist</code> could even be an integer or another map. What would be the ideal solution in this case?</p></pre>the_jester: <pre><p>You can unmarshal JSON into concrete type structs: <a href="http://blog.golang.org/json-and-go" rel="nofollow">http://blog.golang.org/json-and-go</a> - this can be done even with optional fields, just include named fields for the expected values, and the ones not present in the JSON will be skipped.</p>
<p>Which is firmly preferable to do unless you have NO IDEA ahead of time what form your JSON data will take, in which case:</p>
<ul>
<li>Your life will be full of pain since you are getting fed arbitrary data, and</li>
<li>Your code will end up looking pretty close to what you alread have.</li>
</ul></pre>lonahex: <pre><p>The thing is that it is not actually JSON. My function receives <code>map[interface{}]interface{}</code> as input and I don't have control over it. I guess in this case, I'm pretty much stuck with what I have. Thanks for the help!</p></pre>the_jester: <pre><p>Structurally speaking, whoever is passing you map/interface/interface is doing the dirty deed. That is a worthless data type that should be killed off at the first unmarshal step in a program.</p>
<p>However if you know anything about that data - I.E. "it will have either a list or a string in each tuple", then even though the caller was too lazy to do it, your code can structure the data; define your struct, marshal into it "manually", and use that data for your loop & test.</p></pre>danredux: <pre><p>I'm not sure why no one recommended this, makes me think I might be misunderstanding your question, but reflect.DeepEqual seems to do exactly what you want.:</p>
<p><a href="https://play.golang.org/p/oggz_D4-jQ" rel="nofollow">https://play.golang.org/p/oggz_D4-jQ</a></p></pre>rwbcxrz: <pre><p>You could achieve the same results using type assertions, but it's still not pretty:</p>
<pre><code>func checkMap(m map[interface{}]interface{}, listName, test string) bool {
_list, ok := m[listName] // see if m has a key of listName
if !ok {
return false
}
list, ok := _list.([]interface{}) // try to coerce _list into a []interface
if !ok {
return false
}
for _, listItem := range list {
if child, ok := listItem.(string); ok {
if test == child {
return true
}
}
}
return false
}
sampleMap := map[interface{}]interface{}{
"some-string": []interface{}{"value1", "value2"},
}
fmt.Println(checkMap(sampleMap, "some-string", "value1")) // true
fmt.Println(checkMap(sampleMap, "some-string", "bogus")) // false
fmt.Println(checkMap(sampleMap, "bogus", "value1")) // false
</code></pre>
<p>Overall, I'd recommend refactoring the <code>map[interface{}]interface{}</code> into a more concrete type, but it's hard to say whether that's possible without more context.</p></pre>lonahex: <pre><blockquote>
<p>list, ok := _list.([]interface{}) // try to coerce _list into a []interface</p>
</blockquote>
<p>The things is not that I don't know if it'll be present or not, but I don't even know if it'll be a list or not. It could very well be an integer, a string or another map. I guess this would fail in that case.</p>
<blockquote>
<p>Overall, I'd recommend refactoring the map[interface{}]interface{} into a more concrete type, but it's hard to say whether that's possible without more context.</p>
</blockquote>
<p>I thought of that but the input is totally out of my control and I cannot influence it's overall structure in any way. Is there still a better way?</p></pre>shovelpost: <pre><p>So you are basically saying that you are the one that chose to have map[interface{}]interface{} as a function input. This is bad practice regardless of the fact that "you are not sure about the JSON input". If you really want us to help give us examples of that JSON input in all it's forms. I am pretty sure there is a much better way to handle this.</p></pre>lonahex: <pre><p>I'm not choosing it. It is a library I use that works like this. Actually, the library has a call that accepts a function as an argument and passes this beast to it which I have to process. Unfortunately for some reason, I cannot replace the lib with something else right now.</p></pre>
Please suggest a better way for deep child comparison on map[interface{}]interface{}
xuanbao · · 469 次点击这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传