Go语言创建map是否涉及临时匿名对象?如何无临时对象初始化?
我长期使用C/C开发,刚学习Go语言,习惯将Go语法与C/C类比。我了解到创建并初始化string到int类型map的两种方式:
var foo = map[string]int{}
或
var foo = make(map[string]int)
从C/C++视角看,等号的用法看起来像是将默认初始化的变量foo赋值给一个map[string]int类型的临时匿名对象。(虽然对make()的解释未令我满意,但因make()似乎会返回对象并赋值给foo,我仍觉得存在隐式临时匿名对象)
我的问题:
- 上述两种语句是否涉及从临时匿名对象赋值?
- 如果是,如何在Go中实例化(并默认初始化)map对象而不涉及任何临时匿名对象?
我已尝试以下写法,但均在Go中无效:
var foo map[string]int
var foo map[string]int{}
我将此Go语法类比为C++的如下写法:
std::map<std::string, int> foo;
对比
std::map<std::string, int> foo = std::map<std::string, int>();
1. 两种初始化方式是否涉及临时匿名对象赋值?
都不涉及临时匿名对象的赋值操作,这两种写法本质上都是直接初始化变量foo为一个可用的map实例,和C++的赋值语义完全不同:
var foo = map[string]int{}:这是Go的复合字面量初始化语法,编译器会直接为foo分配并初始化一个空的可用map实例,不存在临时对象,也没有先默认初始化再赋值的过程,是一次性完成变量的声明与初始化。var foo = make(map[string]int):make是Go内置的专用于初始化切片、map、通道的函数,它会直接返回一个已完成初始化的可用map实例,这里的“赋值”只是将该实例的引用(Go中map属于引用类型)绑定到变量foo,同样没有临时匿名对象的创建与销毁。
你产生“临时对象”的误解,是因为沿用了C的赋值逻辑,但Go的var 变量 = 值语法属于直接初始化,并非先默认初始化变量再执行赋值操作,这和C中T var = T()的语义有本质区别。
2. 如何无临时对象地实例化map?
其实你最初了解的两种写法就完全满足需求,因为它们本来就不涉及临时匿名对象。另外你尝试的var foo map[string]int是合法的,但它仅完成了map类型变量的声明,并未进行初始化——map类型的零值是nil,处于该状态的map无法直接执行添加、修改键值对等操作,必须初始化后才能使用。
如果你想要更贴近C++std::map<std::string, int> foo;(声明即得到可用实例)的写法,可以使用Go的短变量声明语法:
foo := make(map[string]int)
或者
foo := map[string]int{}
这两种写法和之前的var版本本质一致,都是直接初始化出可用的map实例,不存在临时对象。
你尝试的var foo map[string]int{}属于语法错误,因为map[string]int{}是复合字面量,不能直接跟在类型后用于var声明的初始化,正确写法是var foo = map[string]int{}。
内容的提问来源于stack exchange,提问作者StoneThrow

