1. 综述

变量声明时未赋初值,则变量被自动赋值为该类型的零值(固定值)

func new(Type) *Type

new()返回一个指针,指向新分配的该类型的零值,不是空指针(nil)。the value returned is a pointer to a newly allocated zero value of that type.

func make(t Type, size ...IntegerType) Type

make()只适用于slicemapchan,此三种类型创建时推荐使用make()而不是new()The make built-in function allocates and initializes an object of type slice, map, or chan (only). Unlike new, make's return type is the same as the type of its argument, not a pointer to it. The specification of the result depends on the type:

Slice: The size specifies the length. The capacity of the slice is equal to its length. A second integer argument may be provided to specify a different capacity; it must be no smaller than the length. For example, make([]int, 0, 10) allocates an underlying array of size 10 and returns a slice of length 0 and capacity 10 that is backed by this underlying array.
Map: An empty map is allocated with enough space to hold the specified number of elements. The size may be omitted, in which case a small starting size is allocated.
Channel: The channel's buffer is initialized with the specified buffer capacity. If zero, or the size is omitted, the channel is unbuffered.

如下将按照类型实体、指针、new/make、类型比较等详述各种数据类型。

2. 数组

数组是值类型而不是引用类型。当数组赋值给一个变量时,该变量会得到一个原始数组的副本。对新变量的更改,不会影响原始数组。

数组实体被初始化数组值类型的零值,如int零值为0string零值为""

数组指针初始化为nil

new()返回指向类型零值的指针。 

数组是值类型,可以直接比较。

package main

import (
    "fmt"
    "strconv"
)

func main(){
    var ai [10]int
    var as [10]string
    fmt.Printf("int array [%p] init value: %v\n", &ai, ai)
    fmt.Printf("string array [%p] init value: %v\n", &as, as)
    fmt.Println("---------------------------")

    var i int
    for i = 0; i < len(ai); i++ {
        ai[i] = 100 + i
    }

    for i, _ := range as {
        as[i] = strconv.Itoa(100 + i)
    }
    fmt.Printf("int array [%p] init value: %v\n", &ai, ai)
    fmt.Printf("string array [%p] init value: %v\n", &as, as)
    fmt.Println("---------------------------")

    var pai *[10]int
    var pas *[10]string
    fmt.Printf("int point array [%p] init value: %v\n", &pai, pai)
    fmt.Printf("string point array [%p] init value: %v\n", &pas, pas)
    fmt.Println("---------------------------")

    pai = &ai
    pas = &as
    pai[0] = 1
    pas[0] = "1"
    fmt.Printf("int point array [%p] init value: %v\n", &pai, *pai)
    fmt.Printf("string point array [%p] init value: %v\n", &pas, *pas)
    fmt.Println("---------------------------")

    paii := new([10]int)
    pass := new([10]string)
    fmt.Printf("int point array [%p] init value: %v\n", &paii, *paii)
    fmt.Printf("string point array [%p] init value: %v\n", &pass, *pass)
    fmt.Println("---------------------------")

    for i = 0; i < len(*paii); i++ {
        paii[i] = 100 + i
    }
    for i, _ := range *pass {
        pass[i] = strconv.Itoa(100 + i)
    }
    fmt.Printf("int point array [%p] init value: %v\n", &paii, *paii)
    fmt.Printf("string point array [%p] init value: %v\n", &pass, *pass)
    fmt.Println("---------------------------")

    paii[0] = 1
    pass[0] = "1"
    fmt.Printf("%v\n==\n%v \n???\n%t\n", ai, *paii, (ai==*paii))
    fmt.Println("---------------------------")
    fmt.Printf("%v\n==\n%v \n???\n%t\n", as, *pass, (as==*pass))
}

运行结果:

int array [0xc000072000] init value: [0 0 0 0 0 0 0 0 0 0]
string array [0xc000074000] init value: [         ]
---------------------------
int array [0xc000072000] init value: [100 101 102 103 104 105 106 107 108 109]
string array [0xc000074000] init value: [100 101 102 103 104 105 106 107 108 109]
---------------------------
int point array [0xc00000e030] init value: <nil>
string point array [0xc00000e038] init value: <nil>
---------------------------
int point array [0xc00000e030] init value: [1 101 102 103 104 105 106 107 108 109]
string point array [0xc00000e038] init value: [1 101 102 103 104 105 106 107 108 109]
---------------------------
int point array [0xc00000e040] init value: [0 0 0 0 0 0 0 0 0 0]
string point array [0xc00000e048] init value: [         ]
---------------------------
int point array [0xc00000e040] init value: [100 101 102 103 104 105 106 107 108 109]
string point array [0xc00000e048] init value: [100 101 102 103 104 105 106 107 108 109]
---------------------------
[1 101 102 103 104 105 106 107 108 109]
==
[1 101 102 103 104 105 106 107 108 109]
???
true
---------------------------
[1 101 102 103 104 105 106 107 108 109]
==
[1 101 102 103 104 105 106 107 108 109]
???
true

  

3. 切片

切片是值类型而不是引用类型。切片本身不拥有任何数据,只是对现有数组的引用。对切片的所有修改都会反映到底层数组上。

切片实体初始化为切片类型的零值 nil。一个 nil 切片的长度和容量为 0

切片指针初始化为nil

make返回类型零值的切片,非nil

切片只能和nil作比较,要比较切片需比较切片的每个元素值。

package main

import (
    "fmt"
    "strconv"
)

func main(){
    var si []int
    var ss []string
    fmt.Printf("int slice [%p] init value: %v, len:%d, cap:%d\n", &si, si, len(si), cap(si))
    fmt.Printf("string slice [%p] init value: %v, len:%d, cap:%d\n", &ss, ss, len(ss), cap(ss))
//    fmt.Printf("int slice [%p] init value: %v\n", &si, si[0])
//    fmt.Printf("string slice [%p] init value: %v\n", &ss, ss[0])
    fmt.Println("---------------------------------------")

    var i int
    if si == nil {
        for i = 0; i < 10; i++ {
            si = append(si, 100+i)
            fmt.Printf("int slice [%p] append %d element: %v, len:%d, cap:%d\n", &si, i, si, len(si), cap(si))
        }
    }
    fmt.Println("---------------------------------------")
    if ss == nil {
        for i = 0; i < 10; i++ {
            ss = append(ss, strconv.Itoa(100+i))
            fmt.Printf("string slice [%p] append %d element: %v, len:%d, cap:%d\n", &ss, i, ss, len(ss), cap(ss))
        }
    }
    fmt.Println("---------------------------------------")

    var psi *[]int
    var pss *[]string
//    fmt.Printf("int slice pointer [%p] init value: %v, len:%d, cap:%d\n", &psi, psi, len(*psi), cap(*psi))
//    fmt.Printf("string slice pointer [%p] init value: %v, len:%d, cap:%d\n", &pss, pss, len(*pss), cap(*pss))
    fmt.Printf("int slice pointer [%p] init value: %v\n", &psi, psi)
    fmt.Printf("string slice pointer [%p] init value: %v\n", &pss, pss)
    fmt.Println("---------------------------------------")
    psi = &si
    pss = &ss
    fmt.Printf("int slice pointer [%p] init value: %v, len:%d, cap:%d\n", &psi, *psi, len(*psi), cap(*psi))
    fmt.Printf("string slice pointer [%p] init value: %v, len:%d, cap:%d\n", &pss, *pss, len(*pss), cap(*pss))
    fmt.Println("---------------------------------------")

    sim := make([]int, 10, 10)
    ssm := make([]string, 10, 10)
    fmt.Printf("int slice make [%p] init value: %v, len:%d, cap:%d\n", &sim, sim, len(sim), cap(sim))
    fmt.Printf("string slice make [%p] init value: %v, len:%d, cap:%d\n", &ssm, ssm, len(ssm), cap(ssm))
    fmt.Println("---------------------------------------")

    for i = 0; i < len(sim); i++ {
        sim[i] = 100 + i
    }
    for i,_ := range ssm {
        ssm[i] = strconv.Itoa(100+i)
    }
    fmt.Printf("int slice make [%p] init value: %v, len:%d, cap:%d\n", &sim, sim, len(sim), cap(sim))
    fmt.Printf("string slice make [%p] init value: %v, len:%d, cap:%d\n", &ssm, ssm, len(ssm), cap(ssm))
    fmt.Println("---------------------------------------")

//    fmt.Printf("%v\n==\n%v\n???\n%t\n", si, *psi, (si==*psi))
    fmt.Println("---------------------------------------")
//    fmt.Printf("%v\n==\n%v\n???\n%t\n", ss, ssm, (ss==ssm))

}

运行结果:

int slice [0xc00006a020] init value: [], len:0, cap:0
string slice [0xc00006a040] init value: [], len:0, cap:0
---------------------------------------
int slice [0xc00006a020] append 0 element: [100], len:1, cap:1
int slice [0xc00006a020] append 1 element: [100 101], len:2, cap:2
int slice [0xc00006a020] append 2 element: [100 101 102], len:3, cap:4
int slice [0xc00006a020] append 3 element: [100 101 102 103], len:4, cap:4
int slice [0xc00006a020] append 4 element: [100 101 102 103 104], len:5, cap:8
int slice [0xc00006a020] append 5 element: [100 101 102 103 104 105], len:6, cap:8
int slice [0xc00006a020] append 6 element: [100 101 102 103 104 105 106], len:7, cap:8
int slice [0xc00006a020] append 7 element: [100 101 102 103 104 105 106 107], len:8, cap:8
int slice [0xc00006a020] append 8 element: [100 101 102 103 104 105 106 107 108], len:9, cap:16
int slice [0xc00006a020] append 9 element: [100 101 102 103 104 105 106 107 108 109], len:10, cap:16
---------------------------------------
string slice [0xc00006a040] append 0 element: [100], len:1, cap:1
string slice [0xc00006a040] append 1 element: [100 101], len:2, cap:2
string slice [0xc00006a040] append 2 element: [100 101 102], len:3, cap:4
string slice [0xc00006a040] append 3 element: [100 101 102 103], len:4, cap:4
string slice [0xc00006a040] append 4 element: [100 101 102 103 104], len:5, cap:8
string slice [0xc00006a040] append 5 element: [100 101 102 103 104 105], len:6, cap:8
string slice [0xc00006a040] append 6 element: [100 101 102 103 104 105 106], len:7, cap:8
string slice [0xc00006a040] append 7 element: [100 101 102 103 104 105 106 107], len:8, cap:8
string slice [0xc00006a040] append 8 element: [100 101 102 103 104 105 106 107 108], len:9, cap:16
string slice [0xc00006a040] append 9 element: [100 101 102 103 104 105 106 107 108 109], len:10, cap:16
---------------------------------------
int slice pointer [0xc00007e020] init value: <nil>
string slice pointer [0xc00007e028] init value: <nil>
---------------------------------------
int slice pointer [0xc00007e020] init value: [100 101 102 103 104 105 106 107 108 109], len:10, cap:16
string slice pointer [0xc00007e028] init value: [100 101 102 103 104 105 106 107 108 109], len:10, cap:16
---------------------------------------
int slice make [0xc00006a340] init value: [0 0 0 0 0 0 0 0 0 0], len:10, cap:10
string slice make [0xc00006a360] init value: [         ], len:10, cap:10
---------------------------------------
int slice make [0xc00006a340] init value: [100 101 102 103 104 105 106 107 108 109], len:10, cap:10
string slice make [0xc00006a360] init value: [100 101 102 103 104 105 106 107 108 109], len:10, cap:10
---------------------------------------
---------------------------------------

4. map

Map是引用类型当 map 被赋值为一个新变量的时候,它们指向同一个内部数据结构。因此,改变其中一个变量,就会影响到另一变量。

map的零值是nil,不能插入元素。map没有容量的概念,其长度为目前元素的个数。

只要map不为nil就可以无限插入元素。“map[]=”插入元素。

map实体初始化为nil。需要make()或“=map[int]int{}”进行初始化后才能加元素。

map指针初始化为nil

make返回类型零值的map,且长度为0,无论make中是否指定len或指定len大小。

map只能和nil作比较。要比较map,需比较两个map的每个元素。

package main

import (
    "fmt"
    "strconv"
)

func main(){
    var mi map[int]int
    var ms map[string]string
    fmt.Printf("int map [%p] init value: %v, len:%d\n", &mi, mi, len(mi))
    fmt.Printf("string map [%p] init value: %v, len:%d\n", &ms, ms, len(ms))
    fmt.Println("-------------------------------")

    var i int
    if mi == nil {
        mi = make(map[int]int)
        fmt.Printf("int map make [%p] init value: %v, len:%d\n", &mi, mi, len(mi))
        for i = 0; i < 10; i++ {
            mi[i] = 100 + i
            fmt.Printf("int map make [%p] init %d value: %v, len:%d\n", &mi, i, mi, len(mi))
        }
    }
    fmt.Println("-------------------------------")

    if ms == nil {
        ms = make(map[string]string, 10)
        fmt.Printf("string map make [%p] init value: %v, len:%d\n", &ms, ms, len(ms))
        for i = 0; i < 10; i++ {
            k := strconv.Itoa(100+i)
            ms[k] = strconv.Itoa(100+i)
            fmt.Printf("string map make [%p] init [%v] value: %v, len:%d\n", &ms, k, ms, len(ms))
        }
    }
    fmt.Println("-------------------------------")

    var pmi *map[int]int
    var pms *map[string]string
//    fmt.Printf("int map pointer [%p] init value: %v, len:%d\n", &pmi, pmi, len(*pmi))
//    fmt.Printf("string map pointer [%p] init value: %v, len:%d\n", &pms, pms, len(*pms))
    fmt.Printf("int map pointer [%p] init value: %v\n", &pmi, pmi)
    fmt.Printf("string map pointer [%p] init value: %v\n", &pms, pms)
    fmt.Println("-------------------------------")

    pmi = &mi
    pms = &ms
    fmt.Printf("int map pointer [%p] init value: %v, len:%d\n", &pmi, pmi, len(*pmi))
    fmt.Printf("string map pointer [%p] init value: %v, len:%d\n", &pms, pms, len(*pms))
    fmt.Println("-------------------------------")

//    fmt.Printf("%v\n==%v\n???\n%t\n", mi, *pmi, (mi==*pmi))
    fmt.Println("-------------------------------")
//    fmt.Printf("%v\n==%v\n???\n%t\n", ms, *pms, (ms==*pms))

    var mii map[int]int = map[int]int{}
    var mss map[string]string = map[string]string{}
    fmt.Printf("int map [%p] init value: %v, len:%d\n", &mii, mii, len(mii))
    fmt.Printf("string map [%p] init value: %v, len:%d\n", &mss, mss, len(mss))
    fmt.Println("-------------------------------")

    for i = 0; i < 10; i++ {
        mii[i] = 100 + i
    }

    for i = 0; i < 10; i++ {
        k := strconv.Itoa(100+i)
        mss[k] = strconv.Itoa(100+i)
    }
    fmt.Printf("int map [%p] init value: %v, len:%d\n", &mii, mii, len(mii))
    fmt.Printf("string map [%p] init value: %v, len:%d\n", &mss, mss, len(mss))
    fmt.Println("-------------------------------")
}

运行结果:

int map [0xc00007e018] init value: map[], len:0
string map [0xc00007e020] init value: map[], len:0
-------------------------------
int map make [0xc00007e018] init value: map[], len:0
int map make [0xc00007e018] init 0 value: map[0:100], len:1
int map make [0xc00007e018] init 1 value: map[0:100 1:101], len:2
int map make [0xc00007e018] init 2 value: map[0:100 1:101 2:102], len:3
int map make [0xc00007e018] init 3 value: map[0:100 1:101 2:102 3:103], len:4
int map make [0xc00007e018] init 4 value: map[0:100 1:101 2:102 3:103 4:104], len:5
int map make [0xc00007e018] init 5 value: map[0:100 1:101 2:102 3:103 4:104 5:105], len:6
int map make [0xc00007e018] init 6 value: map[0:100 1:101 2:102 3:103 4:104 5:105 6:106], len:7
int map make [0xc00007e018] init 7 value: map[0:100 1:101 2:102 3:103 4:104 5:105 6:106 7:107], len:8
int map make [0xc00007e018] init 8 value: map[0:100 1:101 2:102 3:103 4:104 5:105 6:106 7:107 8:108], len:9
int map make [0xc00007e018] init 9 value: map[0:100 1:101 2:102 3:103 4:104 5:105 6:106 7:107 8:108 9:109], len:10
-------------------------------
string map make [0xc00007e020] init value: map[], len:0
string map make [0xc00007e020] init [100] value: map[100:100], len:1
string map make [0xc00007e020] init [101] value: map[100:100 101:101], len:2
string map make [0xc00007e020] init [102] value: map[100:100 101:101 102:102], len:3
string map make [0xc00007e020] init [103] value: map[100:100 101:101 102:102 103:103], len:4
string map make [0xc00007e020] init [104] value: map[100:100 101:101 102:102 103:103 104:104], len:5
string map make [0xc00007e020] init [105] value: map[100:100 101:101 102:102 103:103 104:104 105:105], len:6
string map make [0xc00007e020] init [106] value: map[100:100 101:101 102:102 103:103 104:104 105:105 106:106], len:7
string map make [0xc00007e020] init [107] value: map[100:100 101:101 102:102 103:103 104:104 105:105 106:106 107:107], len:8
string map make [0xc00007e020] init [108] value: map[100:100 101:101 102:102 103:103 104:104 105:105 106:106 107:107 108:108], len:9
string map make [0xc00007e020] init [109] value: map[100:100 101:101 102:102 103:103 104:104 105:105 106:106 107:107 108:108 109:109], len:10
-------------------------------
int map pointer [0xc00007e030] init value: <nil>
string map pointer [0xc00007e038] init value: <nil>
-------------------------------
int map pointer [0xc00007e030] init value: &map[0:100 1:101 2:102 3:103 4:104 5:105 6:106 7:107 8:108 9:109], len:10
string map pointer [0xc00007e038] init value: &map[100:100 101:101 102:102 103:103 104:104 105:105 106:106 107:107 108:108 109:109], len:10
-------------------------------
-------------------------------
int map [0xc00007e040] init value: map[], len:0
string map [0xc00007e048] init value: map[], len:0
-------------------------------
int map [0xc00007e040] init value: map[0:100 1:101 2:102 3:103 4:104 5:105 6:106 7:107 8:108 9:109], len:10
string map [0xc00007e048] init value: map[100:100 101:101 102:102 103:103 104:104 105:105 106:106 107:107 108:108 109:109], len:10
-------------------------------

5. struct

结构体是值类型,可以直接用=赋值。

结构体实体初始化为每个成员的零值,仅为某些字段指定初始值时,忽略的字段会赋值为零值。

结构体指针值为nil

new()返回指向类型零值的指针。

如果它的每一个字段都是可比较的,则该结构体也是可比较的。如果两个结构体变量的对应字段相等,则这两个变量也是相等的。如果结构体包含不可比较的字段,则结构体变量也不可比较。

map可以以指针和实体方式返回,函数返回后可以通过返回值访问到原来函数内部的结构体(即函数内部的结构体不会随着函数结束而被回收)。

package main

import (
    "fmt"
)

type People struct {
    Name string
    Phone string
    Addr []string
}

func main(){
    var pStruct People
//    if pStruct == nil {
//        fmt.Println("var initvalue is null")
//    } else {
        fmt.Println("var initvalue init: ",pStruct)
        fmt.Println("var initvalue init: Name: ", pStruct.Name)
        fmt.Println("var initvalue init: Name: ", pStruct.Phone)
        fmt.Println("var initvalue init: Name: ", pStruct.Addr, ", len:", len(pStruct.Addr))
        pStruct =  People{"wang", "123456", []string{"Beijing", "Shanghai"}}
        fmt.Println("after var initvalue init: ", pStruct)
//    }
    fmt.Println("-------------------------------------------")

    var p *People
    if p == nil {
        fmt.Println("pointer initvalue is null")
    } else {
        fmt.Println("pointer initvalue is ", p)
    }

    fmt.Println("-------------------------------------------")
    peo := new(People)
    if peo == nil {
        fmt.Println("new struct initvalue is null")
    } else {
        fmt.Println("new struct initvalue is ", peo)
        peo.Name = "wang"
        peo.Phone = "123456"
        fmt.Println("after new struct initvalue is ", peo)
    }
    fmt.Println("-------------------------------------------")

    tmp, _ := testReturn()
    fmt.Printf("return [%p] value: %v\n", &tmp, tmp)
    fmt.Println("-------------------------------------------")

    ptmp, _ := testReturnPointer()
    fmt.Printf("return pointer [%p]:[%p] value: %v\n", &ptmp, ptmp, *ptmp)
    fmt.Println("-------------------------------------------")
}
func testReturnPointer()(*People, error){
    tmp := People{}
    tmp.Name = "wang"
    tmp.Phone = "123"
    fmt.Printf("In function, return pointer [%p] value: %v\n", &tmp, tmp)
    return &tmp, nil
}

func testReturn()(People, error){
    tmp := People{}
    tmp.Name = "wang"
    tmp.Phone = "123"
    fmt.Printf("In function, return [%p] value: %v\n", &tmp, tmp)
    return tmp, nil
}

运行结果:

var initvalue init:  {  []}
var initvalue init: Name:
var initvalue init: Name:
var initvalue init: Name:  [] , len: 0
after var initvalue init:  {wang 123456 [Beijing Shanghai]}
-------------------------------------------
pointer initvalue is null
-------------------------------------------
new struct initvalue is  &{  []}
after new struct initvalue is  &{wang 123456 []}
-------------------------------------------
In function, return [0xc0000841c0] value: {wang 123 []}
return [0xc000084180] value: {wang 123 []}
-------------------------------------------
In function, return pointer [0xc000084280] value: {wang 123 []}
return pointer [0xc00007e020]:[0xc000084280] value: {wang 123 []}
-------------------------------------------
12-20 09:20