教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Golang Map元素取址问题: cannot assign to struct field XXXX in map

Golang Map元素取址问题: cannot assign to struct field XXXX in map

发布时间:2022-01-08   编辑:jiaochengji.com
教程集为您提供Golang Map元素取址问题: cannot assign to struct field XXXX in map等资源,欢迎您收藏本站,我们将为您提供最新的Golang Map元素取址问题: cannot assign to struct field XXXX in map资源
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"/></svg>

问题描述 :golang 中对 map 类型中的 struct 赋值报错

<pre><code class="lang-go hljs"><span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token string">"fmt"</span> <span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">type</span> Entity <span class="token keyword">struct</span> <span class="token punctuation">{</span> Value <span class="token builtin">string</span> <span class="token punctuation">}</span> entityMap <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">string</span><span class="token punctuation">]</span>Entity<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span> entityMap<span class="token punctuation">[</span><span class="token string">"cat"</span><span class="token punctuation">]</span> <span class="token operator">=</span> Entity<span class="token punctuation">{</span>Value<span class="token punctuation">:</span> <span class="token string">"This is a cat"</span><span class="token punctuation">}</span> entityMap<span class="token punctuation">[</span><span class="token string">"cat"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>Value<span class="token operator">=</span> <span class="token string">"This is a another cat"</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"value "</span><span class="token punctuation">,</span>entityMap<span class="token punctuation">[</span><span class="token string">"cat"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>Value<span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre>

第12行编译报错 : cannot assign to struct field entityMap[“cat”].Value in map

原因是 map 元素是无法取址的,也就说可以得到 a[“tao”], 但是无法对其进行修改。

解决办法:使用指针的map

<pre><code class="lang-go hljs"><span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token string">"fmt"</span> <span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"Hello, World!"</span><span class="token punctuation">)</span> <span class="token keyword">type</span> Entity <span class="token keyword">struct</span> <span class="token punctuation">{</span> Value <span class="token builtin">string</span> <span class="token punctuation">}</span> entityMap <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">string</span><span class="token punctuation">]</span><span class="token operator">*</span>Entity<span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span> entityMap<span class="token punctuation">[</span><span class="token string">"cat"</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token operator">&</span>Entity<span class="token punctuation">{</span>Value<span class="token punctuation">:</span> <span class="token string">"This is a cat"</span><span class="token punctuation">}</span> entityMap<span class="token punctuation">[</span><span class="token string">"cat"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>Value <span class="token operator">=</span> <span class="token string">"This is a another cat"</span> fmt<span class="token punctuation">.</span><span class="token function">Println</span><span class="token punctuation">(</span><span class="token string">"value "</span><span class="token punctuation">,</span>entityMap<span class="token punctuation">[</span><span class="token string">"cat"</span><span class="token punctuation">]</span><span class="token punctuation">.</span>Value<span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre>

golang里面的map是通过hashtable来实现的,具体方式就是通过拉链法(数组 链表)来实现的,这里对比c 的map,c 里面的map, 是通过红黑树来实现的。
所以二者在遍历的时候做删除操作,golang的是可以直接操作的,因为内部实现是哈希映射,删除并不影响其他项,而c 中的map删除,由于是红黑树,删除任意一项,都会打乱迭代指针,不能再O(1)时间内删除。

同时,golang里面的key是无序的,即使你顺序添加,遍历的时候也是无序。

golang里面的map,当通过key获取到value时,这个value是不可寻址的,因为map 会进行动态扩容,当进行扩展后,map的value就会进行内存迁移,其地址发生变化,所以无法对这个value进行寻址。也就是造成上述问题的原因所在。map的扩容与slice不同,那么map本身是引用类型,作为形参或返回参数的时候,传递的是值的拷贝,而值是地址,扩容时也不会改变这个地址。而slice的扩容,会导致地址的变化。

MAP的原理

<pre><code class="lang-go hljs"><span class="token keyword">type</span> hmap <span class="token keyword">struct</span> <span class="token punctuation">{</span> count <span class="token builtin">int</span> <span class="token comment">//元素个数</span> flags <span class="token builtin">uint8</span> B <span class="token builtin">uint8</span> <span class="token comment">//扩容常量</span> noverflow <span class="token builtin">uint16</span> <span class="token comment">//溢出 bucket 个数</span> hash0 <span class="token builtin">uint32</span> <span class="token comment">//hash 种子</span> buckets unsafe<span class="token punctuation">.</span>Pointer <span class="token comment">//bucket 数组指针</span> oldbuckets unsafe<span class="token punctuation">.</span>Pointer <span class="token comment">//扩容时旧的buckets 数组指针</span> nevacuate <span class="token builtin">uintptr</span> <span class="token comment">//扩容搬迁进度</span> extra <span class="token operator">*</span>mapextra <span class="token comment">//记录溢出相关</span> <span class="token punctuation">}</span> <span class="token keyword">type</span> bmap <span class="token keyword">struct</span> <span class="token punctuation">{</span> tophash <span class="token punctuation">[</span>bucketCnt<span class="token punctuation">]</span><span class="token builtin">uint8</span> <span class="token comment">// Followed by bucketCnt keys </span> <span class="token comment">//and then bucketan Cnt values </span> <span class="token comment">// Followed by overflow pointer.</span> <span class="token punctuation">}</span> </code></pre>

每个map的底层结构是hmap,是有若干个结构为bmap的bucket组成的数组,每个bucket可以存放若干个元素(通常是8个),那么每个key会根据hash算法归到同一个bucket中,当一个bucket中的元素超过8个的时候,hmap会使用extra中的overflow来扩展存储key。

到此这篇关于“Golang Map元素取址问题: cannot assign to struct field XXXX in map”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
golang map中结构体元素是无法取地址的
Golang Map元素取址问题: cannot assign to struct field XXXX in map
golang中map地址改变示例
golang map 详解
golang中map的一些注意事项
Golang从入门到放弃200618--Map(1)Map的初始化和基本操作
Golang map 三板斧第二式:注意事项
由浅入深聊聊Golang的map
Golang面试题解析(四)
Golang 中使用多维 map

[关闭]
~ ~