跳转至

golang中关于map的创建初始化问题

之前写python 脚本比较多,对于python中的字典类型数据,创建非常简单,很灵活,但是在golang中有时却很不习惯,从而造成一些困扰。 本文记录一下在golang中创建map的一些细节问题。

golang的变量分为值类型与引用,值类型包括整型、浮点型、bool型、string 数组、结构体 变量地址中直接保存值,对于值类型的变量,声明以后,如果不赋值,那么变量的值为该类型的零值,如整型为0, bool类型为false,golang 的引用类型包括 slice、map、channel、function、pointer 等,如果没有赋值则为nil, 对于nil的变量,是不可以直接使用的。

值类型变量的创建

值类型的数据可以通过var xxx type 来声明,声明的时候可以不赋值,如果不赋值就是默认的零值,也可以使用短变量声明的方式,a := xxx, 这里golang会自己根据后面的值来判断变量的类型.

1
2
3
4
5
6
func main() {
    var s string
    var i int
    ii := false
    fmt.Println(s, i, ii, &s, &i, &ii)
}
以上代码 s为"", i为0,ii为 false,是bool类型。

对于值类型的数据,无论它是否显示的进行初始化,我们在尝试打印它的地址的时候,都可以正常的获取到地址,即变量的地址不是nil

创建map的几种方式

  1. 使用var 方式 使用 var m map[string]int 来声明一个map[string]int 类型的变量,我们来打印一下该变量的内存地址,为 0x0
    1
    2
    3
    4
    5
    6
    7
    8
    func main() {
        var m map[string]int
        if m == nil {
            fmt.Println("m is nil")
        }
    
        fmt.Printf("%p\n", m)
    }
    

当判断是否为nil时,打印出来了 m is nil

当尝试给nil的map 进行赋值时,会直接崩溃 m["age"] = 18, 当执行这段代码时就会panic。

  1. new 方式 new(Type) 方式返回的是*Type, 返回的是一个指针,这里的指针已经不是空指针了,是有具体的内存地址了
    func main() {
    
        m := new(map[string]int)
        if m == nil {
            fmt.Println("m is nil")
        }
    
        fmt.Printf("%p\n", m)
        fmt.Println(*m)
    }
    
    这里判断m==nil 失败.

但是依然不能给这个 m 赋值, (*m)["age"]=18 依然提示是向nil map 赋值, 需要将 m 指向一个具体的值后才可以正常的赋值

1
2
3
4
5
6
7
8
func main() {

    m := new(map[string]int)
    *m = map[string]int{}

    (*m)["name"] = 18
    fmt.Println(*m)
}

  1. make 方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    func main() {
    
        m := make(map[string]int)
        fmt.Printf("%p\n", m)
        fmt.Println(m)
        m["age"] = 9
        fmt.Println(m)
        fmt.Printf("%p\n", m)
    }
    
    使用make方式可以返回一个声明并初始化的变量,对于这个变量,我们可以对其进行直接操作。 上面代码输出为
    1
    2
    3
    4
    0xc00006e180
    map[]
    map[age:9]
    0xc00006e180
    

  2. 声明的时候并初始化 这种方式是比较传统的,可以将其想象成 var s string = "name"

1
2
3
4
5
func main(){
  var m = map[string]int{} //这里的{} 不能少
  m["age"] = 18
  fmt.Pringln(m)
}

json 中的应用

有很多时候,我们将json进行反序列化的时候,会转成结构体或者map,

func main() {
    jstr := `{"name":"yangyanxing", "age": 18}`
    var m map[string]interface{}
    mm := make(map[string]interface{})
    var mmm = map[string]interface{}{}
    var mmmm = new(map[string]interface{})
    json.Unmarshal([]byte(jstr), &m)
    json.Unmarshal([]byte(jstr), &mm)
    json.Unmarshal([]byte(jstr), &mmm)
    json.Unmarshal([]byte(jstr), mmmm)
    fmt.Println(m)
    fmt.Println(mm)
    fmt.Println(mmm)
    fmt.Println(*mmmm)
}

上面四种方式初始化map对象,在json.Unmarshl 方法都可以将json 转为map,注意使用new 返回的本身就是指针了,就不用再用& 取地址符了,其实即使用的取地址符,也可以得到相同的结果。

参考文章

面试官:Golang 的 new 与make 区别是什么?