详解Go中Map类型和Slice类型的传递
作者:snowInPluto 发布时间:2024-04-23 09:47:03
关于 Go 中 Map 类型和 Slice 类型的传递
Map 类型
先看例子 m1:
func main() {
m := make(map[int]int)
mdMap(m)
fmt.Println(m)
}
func mdMap(m map[int]int) {
m[1] = 100
m[2] = 200
}
结果是
map[2:200 1:100]
我们再修改如下 m2:
func main() {
var m map[int]int
mdMap(m)
fmt.Println(m)
}
func mdMap(m map[int]int) {
m = make(map[int]int)
m[1] = 100
m[2] = 200
}
发现结果变成了
map[]
要理解这个问题,需要明确在 Go 中不存在引用传递,所有的参数传递都是值传递。
现在再来分析下,如图:
可能有些人会有疑问,为什么途中的 m 像是一个指针呢。查看官方的 Blog 中有写:
Map types are reference types, like pointers or slices, ...
这边说 Map 类型是引用类型,像是指针或是 Slice(切片)。所以我们基本上可以把它当作是指针来看待(注意,只是近似,或者说其中含有指针,其内部仍然含有其他信息,这里只是为了便于理解),只不过这个指针有些特殊罢了。
m1 中,当调用 mdMap 方法时重新开辟了内存,将 m 的内容,也就是 map 的地址拷贝入了 m',所以此时当操作 map 时,m 和 m' 所指向的内存为同一块,就导致 m 的 map 发生了改变。
而在 m2 中,在调用 mdMap 之前,m 并未分配内存,也就是说并未指向任何的 map 内存区域。从未导致 m' 的 map 修改不能反馈到 m 上。
Slice 类型
现在看一下 Slice。
s1:
func main() {
s := make([]int, 2)
mdSlice(s)
fmt.Println(s)
}
func mdSlice(s []int) {
s[0] = 1
s[1] = 2
}
s2:
func main() {
var s []int
mdSlice(s)
fmt.Println(s)
}
func mdSlice(s []int) {
s = make([]int, 2)
s[0] = 1
s[1] = 2
}
不出所料:
s1 结果为
[1 2]
s2 为
[]
因为正如官方所说,Slice 类型与 Map 类型一样,类似于指针,Slice 中仍然含有长度等信息。
修改一下 s1,变成 s3:
func main() {
s := make([]int, 2)
mdSlice(s)
fmt.Println(s)
}
func mdSlice(s []int) {
s = append(s, 1)
s = append(s, 2)
}
不再修改 slice 原先的两个元素,而加上另外两个,结果为:
[0 0]
发现修改并没有反馈到原先的 slice 上。
这里我们需要把 slice 想象为特殊的指针,其已经保存了所指向内存区域长度,所以 append 之后的内存并不会反映到 main() 中:
那如何才能反映到 main() 中呢?没错,使用指向 Slice 的指针。
func mdSlice(s *[]int) {
*s = append(*s, 1)
*s = append(*s, 2)
}
内存如图所示:
注意本文中内存区域分配是否连续完全随机,不影响程序,只是为了图解清晰。
Chan 类型
Go 中 make 函数能创建的数据类型就 3 类:Slice, Map, Chan。不比多说,相比读者已经能想象 Chan 类型的内存模型了。的确如此,读者可以自己尝试,这边就不过多赘述了。(可以通通过 == nil 的比较来进行测试)。
来源:http://www.cnblogs.com/snowInPluto/p/7477365.html


猜你喜欢
- MySql5.0以后均支持存储过程,最近有空,研究了一把这个。格式:以下为引用的内容:CREATE PROCEDURE
- 背景由于阿里云oss,cdn消耗钱的速度比较快,在不知道的情况下,服务就被停了,影响比较大。所以想做个监控。百度一下阿里云账户余额 api
- 主要讲 except 和 not in 的性能上的区别。 CREATE TABLE tb1(ID int) CREATE TABLE tb2
- 查询速度慢的原因很多,常见如下几种:1、没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷)2、I/O吞吐量小,形成了瓶颈效
- UTF-8包含全世界所有国家需要用到的字符,是国际编码,通用性强。UTF-8编码的文字可以在各国支持UTF8字符集的浏览器上显示。如,如果是
- 啥都不说了,直接奉献原代码 代码如下:'==========注意==================================
- 如下所示:# -*-coding: utf-8 -*-import pandas as pd#读取csv文件df=pd.read_csv(&
- 四种基本的函数类型局部变量 就是在函数内部定义的变量【作用域仅局限于函数内部】不同的函数 可以定义相同的局部变量,但是各自用各自的 不会产生
- ThinkPHP CURD方法的limit方法也是模型类的连贯操作方法之一,主要用于指定查询和操作的数量,特别在分页查询的时候使用较多。并且
- 0.前言添加colormap的对象是灰度图,可以变成热量图,从而更加明显的发现一些规律,适用于一些雷达图像等from PIL import
- 注:本篇文章主要介绍如何在 Go 语言中定义和使用自定义类型,涉及到一定的编程基础知识和语法。如有不熟悉的地方,建议先去学习相关的基础知识。
- 本文实例讲述了Python3.5编程实现修改IIS WEB.CONFIG的方法。分享给大家供大家参考,具体如下:#!/usr/bin/env
- Python3.7 基于 pycryptodome 的AES加密解密、RSA加密解密、加签验签,具体代码如下所示:#!/usr/bin/en
- 一、安装1、安装easy_install工具wget http://peak.telecommunity.com/dist/ez_setup
- 本文实例讲述了Python面向对象封装操作。分享给大家供大家参考,具体如下:目标封装小明爱跑步存放家具01. 封装封装 是面向对象编程的一大
- 与 Python 一样,Go 语言也有空白标识符。1.什么是空白标识符空白标识符是未使用的值的占位符。它由下划线(_)表示。由于空白标识符没
- 使用函数 ugettext() 来指定一个翻译字符串。 作为惯例,使用短别名 _ 来引入这个函数以节省键入时间.在下面这个例子中,文本 &q
- 扩展Code:var blogModule = (function (my) { my.AddPhoto = function (
- 一、定义与作用主键:表中能够唯一地辨别事物的属性。通过主键能够查询出表中一条完整的记录,同时使用主键能防止表中出现重复的记录,避免了数据的冗
- 很多朋友对FrontPage2003中增加的网页布局功能很感兴趣,现在我们一起来深入了解这一实用功能。用FrontPage2003的“布局表