When and why should I use sytucts over maps?

agolangf · · 613 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>As the title says; I do not understand the use of structs. Why should I use them instead of say, maps? Maps have the benefit of letting me store more than one tuples of data. So why and in which use cases should I use structs? Thanks in advance</p> <hr/>**评论:**<br/><br/>oefig: <pre><p>Struct and maps aren&#39;t interchangable. Maps are a flexible collection of data and Structs are schema that defines a data type. Maps hold things and Structs are things.</p></pre>izuriel: <pre><p>Structs not only provide a <em>structured</em> means for grouping data it also provides some documentation by having the field names and types known before hand. Here is a very simplistic example.</p> <p><a href="http://play.golang.org/p/73UQnuT9vl" rel="nofollow">http://play.golang.org/p/73UQnuT9vl</a></p> <p>If I modify this from it&#39;s current stat to just use a map, it won&#39;t run. </p> <p><a href="http://play.golang.org/p/kHDPn3c7Xn" rel="nofollow">http://play.golang.org/p/kHDPn3c7Xn</a></p> <p>The reason is that we have to use a <code>map[string]interface{}</code> to get the same results as the previous <code>SimpleUser</code> struct where we&#39;re storing a <code>string</code> and an <code>int</code>. We can&#39;t create a <code>map[string]string</code> or a <code>map[string]int</code> because neither would allow to fully represent <code>SimpleUser</code>.</p> <p>So how would we fix it using a map? We have to add a cast <code>u[&#34;name&#34;].(string)</code>.</p> <p><a href="http://play.golang.org/p/12ypzf-HRu" rel="nofollow">http://play.golang.org/p/12ypzf-HRu</a></p> <p>Alright, so you might be thinking, &#34;Of course, so why use a struct?&#34; And that&#39;s a good question. Because <code>u[&#34;name&#34;]</code> might not be a <code>string</code>. We cannot make any guarantee that the user&#39;s <code>&#34;name&#34;</code> property will be a <code>string</code>, heck, or even be in the map. Let&#39;s see what that looks like.</p> <p><a href="http://play.golang.org/p/S0LFHdm-bY" rel="nofollow">http://play.golang.org/p/S0LFHdm-bY</a></p> <p>With a struct, those fields are zeroed if not set, and they cannot be assigned the wrong value.</p> <p><a href="http://play.golang.org/p/TvNdHpyjzi" rel="nofollow">http://play.golang.org/p/TvNdHpyjzi</a></p> <p>So, to conclude, you would use structs for safety. Both at compile time, and to provide a meaningful storage method for related data. Just throwing everything into a map works in quite the opposite way, unfortunately. If I were to get a <code>map[string]interface{}</code> back from a library call instead of something like a <code>User struct</code> I would immediately discontinue use because no guarantee could be made now (or ever) on the structure of that map and this could lead to random crashes in my software because of it. I&#39;m not dissuading the use of maps, but maps should be used when representing an unknown grouping of key/value pairs or to relate some common key to an uncommon or expensive to generate value. Structs should be used to group meaningful units of data like a <code>User</code> a <code>Game</code> or any other number of things. I would also recommend if you&#39;re consuming a JSON API to decode into a struct rather than a map, again, no need for additional casts and the data is immediately typed and available. </p></pre>DeltaSixBravo: <pre><p>Type safety when using multiple types and performance. If you need fields of different types in a map, you have to use interface{}, which means you&#39;ll be making a type assertion for almost every lookup, which could fail at runtime instead of compile time. Structs also allow the compiler to know the size and offset of every field at compile time. This means fields can be accessed with a single memory load. Maps, on the other hand, require a hash of the key to be generated, which is then used to lookup the value. A map lookup can be 2 or 3 loads, depending on how the underlying hash table is implemented. </p></pre>BBbk11: <pre><p>First of all did you ever looked how a map and a struct is implemented?</p> <p>The map will store the whole name as string(or whatever you use as key), will use a hash table with Buckets to lookup and the value itself somewhere on the heap. (<a href="http://www.goinggo.net/2013/12/macro-view-of-map-internals-in-go.html" rel="nofollow">http://www.goinggo.net/2013/12/macro-view-of-map-internals-in-go.html</a>)</p> <p>Compared to a struct which is just a &#39;layout&#39; how the memory is &#39;structured&#39;. So the compiler knows at compile time which item is accessed and just need to use the offset which is calculated by the compiler aswell. That costs by far less than looking up an item with a key. And don&#39;t forgot an optimization. Also It&#39;s important that the struct is one block of memory if you use a map you will probably end up having lots of small pieces of memory.</p> <p>Also It allows you to work with other programming languages. However for this I would advice defining the struct in C because that&#39;s basicly more safe because of the alignment.</p> <p>Another important point is that go is a static typed langauge. In alot of places where safety is important(I cann&#39;t proof that, It&#39;s my opinion) static typed language will just make your life easier. The compiler is basicly powerful enough to detect alot of mistakes by enforcing static typing. The probability you make a small typo is kinda high so setting some variables you never wanted to set or to get can be really dangerous. Also It would be hard to differ from public and private fields.</p> <p>I think you should inform abit and also make a performance test once you will notice huge differences.</p></pre>dieckie: <pre><p>Thanks Guys, this helped me a log understanding the differences.</p></pre>pierrrre: <pre><p>For safety?</p></pre>fxnn: <pre><p>Maps store an (at compile time) unknown number of values without ordering, whereas all values have one common, well-known type. Each value is accessed by a key, and again, all keys share one common type.</p> <p>Structs store a <em>known</em> number of values, each of possibly <em>different</em> type, under a name that is known at compile time.</p> <p>Arrays store an unknown number of values, but again, all of the same type. The difference to a map is here, that they ought to be stored with numeric &#34;keys&#34; with a special order.</p> <p>Each thing for its purpose :)</p></pre>Fwippy: <pre><p>Slight correction: Arrays store a known number of values, slices store an unknown number of values.</p></pre>PassifloraCaerulea: <pre><p>The immediate problem is that a map can only hold values of a certain type. You can&#39;t mix strings and numbers, for example. Structs let you do this, and with a little thinking you can usually find a fixed set of elements for it. The other thing is that structs have much less overhead both in cpu time and memory space for the same data.</p> <p>There are many things I could explain, but without knowing where you&#39;re coming from or what specific thing you&#39;re trying to do, it&#39;s hard to give an answer. You can&#39;t just use one in place of the other.</p></pre>mc_hammerd: <pre><p>its two different paradigms (ways of writing code)</p> <p>structs are similar to OOP concepts, most of the time when you use a struct you are going to have many structs:</p> <pre><code>type listitem struct { icon bmp, text string, tooltip string } // quick ex: drawlist([]listitem{ item1,item2 }) func drawlist (list []listitem) { for i,v := range list { fmt.Println(i,&#34;:&#34;, v.text) } fmt.Println(&#34;Choose an item (#):&#34;) } //ex 2: type player struct { mana int, abilityPower int, hp int, act int } if player1.CastsSpell() &amp;&amp; player2.castsSpell() { if player1.abilityPower &gt; player2.abilityPower { // player1 wins } //.. etc } </code></pre> <p>maps are dictionaries/hash tables, kind of like an array but with a lookup key</p> <pre><code>var m map[playerID int]player = {} var player1 = m[1] player1.dostuff() </code></pre> <p>use structs when you will be duplicating common functionality (like player1,player2,badguy), or you need struct methods (player1.isAlive()) or when you will be encoding the data to json</p> <p>structs are also used to read and write binary blob (serialized)/packed/zipped data to files. ex: first 12 bytes are the first field in the struct and its type is INT64, next 36 bytes are type String and that is field 2.</p> <p>structs are also used to interact with hardware drivers, things like USB/serial ports and Arduino/rasperry pi drivers</p></pre>fxnn: <pre><p>In go, you can also declare functions on maps. Also, why shouldn&#39;t you use maps for serialization of JSON data?</p></pre>mc_hammerd: <pre><p>you should use it for json, but the use case is different i believe. i think a map equates to an json array (a list with a unique key of things of the same type == converts to array), while a struct converts to an object.</p></pre>SteveMcQwark: <pre><p>A map also serializes to and deserializes from a JSON object. A struct is just often more useful in Go, since the fields and their types are statically known, as well as being more efficient, since fields are stored directly and at known offsets which don&#39;t need to be computed on each access.</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

613 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传