Golang构造结构体对象new方法和取地址符&的区别

Golang构造结构体对象new方法和取地址符&的区别

面向对象的语言一般都有构造函数,用来在创建对象时初始化对象,即为对象成员变量赋初始值。但是Golang里面没有构造函数,在初始化结构体对象时可以使用new操作符,也可以使用&操作符,两者具体区别在哪里呢?

一、构造函数与复合语义(Constructors and composite literals)

在go官方文档 effective_go 中的 Constructors and composite literals 章节部分指出:

1
2
As a limiting case, if a composite literal contains no fields at all, it creates a zero value for the type. 
The expressions new(File) and &File{} are equivalent.

也就是说,如果在构造结构体时,复合文本中没有包含任何字段,则它将为类型创建一个零值。此时表达式 new(File) 和 &File{} 是等价的。

有时候零值初始化并不够好,所以构造函数还是有必要的,看 package os 包中的一个例子:

1
2
3
4
5
6
7
8
9
10
11
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
f := new(File)
f.fd = fd
f.name = name
f.dirinfo = nil
f.nepipe = 0
return f
}

这种类似早期 C++ 生成对象的写法,看着有点繁琐,而且有时候也容易遗漏某些字段。可以使用复合语义来简化,而且每次调用时都是不同的实例。

1
2
3
4
5
6
7
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
f := File{fd, name, nil, 0}
return &f
}

与 C、C++ 不同,go 语言可以返回局部变量的地址,变量相关联的存储在函数返回后继续存在。合并上述代码的最后两行,进一步简化。

1
return &File{fd, name, nil, 0}

复合文本的字段按顺序排列,并且必须全部存在。但是,通过将元素显式标记为 field:value 对,初始化器可以以任何顺序出现。未出现的字段,则使用对应类型的零值初始化。

1
return &File{fd: fd, name: name}

二、在赋值语句方面的不同

使用new

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
package main

import (
"fmt"
)

type Drink struct {
Name string
Flavour string
}

func main() {
a := new(Drink)
a.Name = "Maaza"
a.Flavour = "Mango"
b := a
fmt.Println(&a)
fmt.Println(&b)
b.Name = "Frooti"
fmt.Println(a.Name)
}

// output
0xc000006028
0xc000006030
Frooti

Process finished with exit code 0

在赋值 = 操作时,虽然 a、b 的地址不同,但是修改了 b 对象的 Name 字段值,a 对象的 Name 字段也改变了。

使用取地址符&

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
package main

import (
"fmt"
)

type Drink struct {
Name string
Flavour string
}

func main() {
a := Drink{
Name: "Maaza",
Flavour: "Mango",
}
b := a
fmt.Println(&a)
fmt.Println(&b)
b.Name = "Froti"
fmt.Println(a.Name)
}

// output
&{Maaza Mango}
&{Maaza Mango}
Maaza

Process finished with exit code 0

这里改变 b 变量 Name 字段的值,不会对 a 变量 Name 字段造成影响。若讲赋值语句修改为 b := &a,即将 b 指向了 a 变量的地址,此时修改 b 的 Name 字段,实际也是在修改 a 变量的 Name 字段。

评论

:D 一言句子获取中...

加载中,最新评论有1分钟缓存...