new
初始化
new(T)
是为T
类型分配一块内存,将内存清零,并返回T
的指针。指针指向的内存是未初始化的(T
类型的零值)。
1
2
3
4
|
func main(){
a := new(int)
fmt.Printf("value of a: %#v\n", a) // 输出:value of a: (*int)(0xc000014660)
}
|
参数
new(T)
中的类型T
可以是Golang中的任意类型,如 int
, slice
, string
, map
, channel
, struct
等等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
func main() {
// int
a := new(int)
fmt.Printf("type of a: %#v\n", reflect.TypeOf(*a).Kind().String())
// 输出: type of a: "int"
// string
b := new(string)
fmt.Printf("type of b: %#v\n", reflect.TypeOf(*b).Kind().String())
// 输出: type of b: "string"
// map
c := new(map[string]int)
fmt.Printf("type of c: %#v\n", reflect.TypeOf(*c).Kind().String())
// 输出: type of c: "map"
// struct
d := new(struct{ name string })
fmt.Printf("type of d: %#v\n", reflect.TypeOf(*d).Kind().String())
// 输出: type of d: "struct"
// 指针
e := new(*int)
fmt.Printf("type of e: %#v\n", reflect.TypeOf(*e).Kind().String())
// 输出: type of e: "ptr"
// slice
e := new([]int)
fmt.Printf("value of pointer e: %#v\n", *e)
// 修改slice
// 【注意】,slice 与 map 类似,零值是nil,需要修改时,只能通过*e=[]int{},而不能通过下标修改
//(*e)[0] = 99 // 输出:panic: runtime error: index out of range [0] with length 0
*e = []int{1, 2, 3}
fmt.Printf("value of pointer e: %#v\n", *e)
// 输出:value of pointer e: []int{1, 2, 3}
}
|
返回值
new(T)
返回的是指针,指向的内存是未初始化的(T
类型的零值)。即new(T)*T
。如果要访问T的值,需要解引用。即*T
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
func main(){
// int
a := new(int)
// 访问 指针a 的值
fmt.Printf("value of pointer a: %#v\n", *a)
// 输出:value of pointer a: 0
// 修改 int类型的值
*a = 99
fmt.Printf("value of pointer a: %#v\n", *a)
// 输出:value of pointer a: 99
// --------------------
// string
b := new(string)
fmt.Printf("value of pointer b: %#v\n", *b)
// 输出: value of pointer a: 0
// 修改 string类型的值
*b = "hello"
fmt.Printf("value of pointer b: %#v\n", *b)
// 输出:value of pointer b: "hello"
// --------------------
// map
c := new(map[string]int)
fmt.Printf("value of pointer c: %#v\n", *c)
// 修改 map 类型的值,
// 【注意】:new(map[T1][T2]) 返回的值`v`是 map 的零值 nil,而不是空map,如果需要修改,只能通过 `v` = map[T1][T2]{},而不能用v[x] = y
// (*c)["age"] = 20 // 输出:panic: assignment to entry in nil map
*c = map[string]int{"age": 20}
fmt.Printf("value of pointer c: %#v\n", *c)
// 输出:map[string]int{"age":20}
// --------------------
// struct
d := new(struct{ name string })
fmt.Printf("value of pointer d: %#v\n", *d)
// 输出:value of pointer d: struct { name string }{name:""}
// 修改struct
(*d).name = "zhangsan"
fmt.Printf("value of pointer d: %#v\n", *d)
// 输出:value of pointer d: struct { name string }{name:"zhangsan"}
}
|
make
初始化
make(T[, args])
为T
类型分配一块内存,并初始化内存以及内置的数据结构,返回T
的引用而不是指针,并且T
的类型只能是slice
、map
或channel
。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
func main() {
a := make([]int, 0)
fmt.Printf("value of a: %v\n", a)
// 输出:value of a: []
b := make(map[string]int)
fmt.Printf("value of b: %v\n", b)
// 输出:value of b: map[]
c := make(chan int)
fmt.Printf("value of c: %v\n", c)
// 输出:value of c: 0xc000090360
}
|
参数
make(T[, args])
中的类型T
只能是 slice
, map
或者 channel
中的其中一个。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
func main() {
// T = slice 需要指定长度,长度大于0时,切片内的元素为make([]T, n)中T的零值
a := make([]int, 0)
fmt.Printf("value of a: %v\n", a)
// 输出:value of a: []
// T = slice
aMap := make([]map[int]int, 1)
fmt.Printf("value of aMap: %#v\n", aMap)
// 输出:value of aMap: []map[int]int{map[int]int(nil)}
// T = map
b := make(map[string]int)
fmt.Printf("value of b: %#v\n", b)
// 输出:value of b: map[]
// T = chan
c := make(chan int)
fmt.Printf("value of c: %#v\n", c)
// 输出:value of c: 0xc000090360
}
|
返回值
make(T [, args]) T
的返回值为 T
的引用,在函数内部可以直接修改原始值
- Slice,返回不再是零值,而是一个空切片,可以通过下标修改元素值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
func main() {
// Slice,初始化内存和数据结构,返回长度=2的[]int类型切片的引用,
//【注意】:这里的s可以通过下标直接修改元素值,如s[1]=999,但下标不可以超过`make(t [,args])`中的`args`参数,会导致溢出。
s := make([]int, 2)
s[1]=999
fmt.Printf("value of s is %#v\n", s) // 输出:value of s is []int{0, 999}
// 修改s的值,在下一行的打印中会生效,说明 `s` 是引用类型
updateSlice(s)
// 上面updateSlice内修改的值,在这里依然生效
fmt.Printf("value of s is updated %#v\n", s) // 输出:value of s is updated []int{99, 999}
}
func updateSlice(s []int) {
s[0] = 99
}
|
- Map,返回的也不是map的零值
nil
,而是一个空map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
func main() {
// Map
m := make(map[string]string)
fmt.Printf("value of m-1: %#v\n", m) // 输出:value of m-1: map[string]string{}
// 修改 map,这里m不再是map的零值,而是一个空map,可以直接修改
m["name"] = "zhangsan"
fmt.Printf("value of m-2: %#v\n", m) // 输出:value of m-2: map[string]string{"name":"zhangsan"}
updateMap(m)
fmt.Printf("value of m-3: %#v\n", m) // 输出:value of m-3: map[string]string{"age":"18", "name":"lisi"}
}
func updateMap(m map[string]string) {
m["name"] = "lisi"
m["age"] = "18"
}
|
- Channel, 返回的并不是chan的零值
nil
,而是一个空channel,可以像channel中写入数据,但如果是通过new
初始化的channel,则初始化之后的channel是零值nil,写入数据会阻塞,并不会报错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
func main() {
ch := make(chan int, 0)
fmt.Printf("value of ch: %#v\n", ch)
ch2 := new(chan int)
fmt.Printf("value of ch2: %#v\n", *ch2)
ch3 := *ch2
go func() {
for {
if v, ok := <-ch3; ok {
fmt.Printf("value of ch3: %v\n", v)
break
}
fmt.Println("loop...")
}
}()
fmt.Println("starting insert number to channel...")
// 【重点】ch3=ch时,这里正常写入数据,因为make返回的是一个空channel;但是如果ch3=*ch2时,这里会阻塞,因为new 返回的*ch2是零值nil,向值为nil的channel写入数据时是会永久阻塞的
ch3 <- 2
}
|
总结
new(T)
是为T
分配内存空间并将空间初始化为T
的零值,返回的是T
的指针并且T
可以使任意数据类型;而make(T [,args])
分配内存空间之后会初始化底层的数据结构,返回的是T
类型数据结构初始化之后的引用,而不是T的零值,并且T
只能是slice
、map
、channel
中的其中一个。