[Go语言]从Docker源码学习Go——指针和Structs

来源:转载

这两天在看reflect这个包在Docker中的使用时,遇到了各种问题,最后虽然知道怎么用了。

但是对于这块的原理还不是太懂,于是把"THE WAY TO GO"中关键的几章看了下。

继续坚持往下写,争取能说明白。

源码

还是先看Docker中源码, docker/api/client/cli.go

type DockerCli struct {

proto string

addr string

configFile *registry.ConfigFile

in io.ReadCloser

out io.Writer

err io.Writer

isTerminal bool

terminalFd uintptr

tlsConfig *tls.Config

scheme string

}

...

func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string, tlsConfig *tls.Config) *DockerCli {

...

return &DockerCli{

proto: proto,

addr: addr,

in: in,

out: out,

err: err,

isTerminal: isTerminal,

terminalFd: terminalFd,

tlsConfig: tlsConfig,

scheme: scheme,

}

}

先定义了一个struct,然后定义一个初始化的方法(方法内部初始化了一个struct,并返回其地址。)

指针

首先介绍一下go中的指针

我们在程序中定义一个变量,它在内存中被分配了一块空间,这块空间内存储的值就是变量的值,而这块空间的地址就可以赋值给一个指针。

指针内存放的是一个变量的内存地址,而不是真实的变量值。

声明一个指针用下面的方式( type 前面带 * 符号)

var intP *int

给指针赋值用 & 符号

i1 := 1

intP = &i1

通过在指针变量前面添加 * 符号,你可以获得指针指向变量的值。

int1 == *(&int1)

在传值过程中尽量使用指针,这可以大大的减少内存开支,并提高传值速度。

不过有一个缺点是,在获得值时,由于多加了一层关系,所以会在这部分的性能上稍微慢一点。

struct使用

struct格式

type identifier struct {

field1 type1

field2 type2

...

}

struct初始化, 看下面例子中的3种情况就明白了。

// main

package main

import "strings"

type Person struct {

firstName string

lastName string

}

func upPerson(p *Person) {

p.firstName = strings.ToUpper(p.firstName)

p.lastName = strings.ToUpper(p.lastName)

}

func main() {

//1 - struct as a value type:

var pers1 Person

pers1.firstName = "Lemon"

pers1.lastName = "Bar"

upPerson(&pers1)

//2 - struct as a pointer:

pers2 := new(Person)

pers2.firstName = "Lemon"

pers2.lastName = "Bar"

//(*pers2).lastName = "Bar" //this is also valid

upPerson(pers2)

//3 - struct as a literal:

pers3 := &Person{"Lemon", "Bar"}

//pers3 := &Person{firstName:"Lemon",lastName:"Bar"} //this is also valid

upPerson(pers3)

}

注:new出来的是指针

我们除了可以直接初始化外,也可以通过定义工厂方法的形式来进行初始化

func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string, tlsConfig *tls.Config) *DockerCli {

...

}

注:如果想让这个struct在所属的package外,只能通过工厂方法来初始化,可以把struct名字的首字母改成小写,也就是private的,package外就只能通过工厂方法进行初始化了。

匿名fields

匿名的fields可以实现其它语言中继承的功能

package main

type innerS struct {

in1 int

in2 int

}

type outerS struct {

b int

c float32

int //anonymous field

innerS //anonymous field

}

func main() {

outer := new(outerS)

outer.in1 = 3 //outerS.in1 is innerS.in1

outer.in2 = 4 //outerS.in2 is innerS.in2

outer.int = 5 //int is also the anonymous filed name

outer2 := outerS{5, 6.7, 20, innerS{3, 4}} //outerS can also be initialized in this format

}

匿名struct里面的filed就变成外面struct的field。

注:在一个struct内,对于每种类型,只能有一个匿名类型的field。

名字冲突问题

由于一个struct里面可以包含多个匿名的不同类型的struct,那当有名字相同的filed时,go怎么处理呢?

1. outer field比inner field优先级更高,也就是外面的会覆盖掉里面的。

2. 如果两个field层级一样

a. 如果这个field名字,没有被用到的话,不会有问题。

b. 如果被用到了,会有编译错误。

 


分享给朋友:
您可能感兴趣的文章:
随机阅读: