这两天在看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 :=
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 = //outerS.in1 is innerS.in1
outer.in2 = //outerS.in2 is innerS.in2
outer.int = //int is also the anonymous filed name outer2 := outerS{, 6.7, , innerS{, }} //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. 如果被用到了,会有编译错误。

[Go语言]从Docker源码学习Go——指针和Structs的更多相关文章

  1. [Go语言]从Docker源码学习Go——结构和函数的定义

    Docker在最近很火,而作为Docker的开发语言-Go也再次被大家提到. 已经使用Docker一段时间了,但是对于源码,尤其是其开发语言Go却一直是一知半解. 最近准备利用空余时间从Docker源 ...

  2. [Go语言]从Docker源码学习Go——function和method

    function和method关系 method是针对某一类型定义的function, function可以单独调用,method必须针对某一类型的实例进行调用 //function 调用方式 pac ...

  3. [Go语言]从Docker源码学习Go——if语句和map结构

    if语句 继续看docker.go文件的main函数 if reexec.Init() { return } go语言的if不需要像其它语言那样必须加括号,而且,可以在判断以前,增加赋值语句 语法 I ...

  4. [Go语言]从Docker源码学习Go——init()方法和identifier首字母大小写区分

    init()方法 如果想在一个go文件里,进行一些初始化的工作,可以把代码放到init()方法中. init()方法先被执行. func init() { // initialization of p ...

  5. [Go语言]从Docker源码学习Go——main函数

    Go程序从main包下的main函数开始执行,当main执行结束后,程序退出. Docker的main函数在 docker/docker/docker.go package main //Import ...

  6. [Go语言]从Docker源码学习Go——Interfaces

    Interface定义: type Namer interface { Method1(param_list) return_type Method2(param_list) return_type ...

  7. Go语言 context包源码学习

    你必须非常努力,才能看起来毫不费力! 微信搜索公众号[ 漫漫Coding路 ],一起From Zero To Hero ! 前言 日常 Go 开发中,Context 包是用的最多的一个了,几乎所有函数 ...

  8. Docker源码分析(三):Docker Daemon启动

    1 前言 Docker诞生以来,便引领了轻量级虚拟化容器领域的技术热潮.在这一潮流下,Google.IBM.Redhat等业界翘楚纷纷加入Docker阵营.虽然目前Docker仍然主要基于Linux平 ...

  9. Docker源码分析(二):Docker Client创建与命令执行

    1. 前言 如今,Docker作为业界领先的轻量级虚拟化容器管理引擎,给全球开发者提供了一种新颖.便捷的软件集成测试与部署之道.在团队开发软件时,Docker可以提供可复用的运行环境.灵活的资源配置. ...

随机推荐

  1. Android低功耗蓝牙(BLE)使用详解

    代码地址如下:http://www.demodashi.com/demo/13390.html 与普通蓝牙相比,低功耗蓝牙显著降低了能量消耗,允许Android应用程序与具有更严格电源要求的BLE设备 ...

  2. Linux-Vim常用操作

    vim wangyunpeng.txt 创建一个wangyunpeng.txt文件 输入"i"进入插入模式 显示行号,需要在命令模式下输入":se nu" cp ...

  3. iOS小知识点记录

    1.创建视图的两种方法:用代码创建视图,创建XIB文件.如何决定使用哪种方法?参考法则:如果视图没有子视图,就用代码创建:如果有子视图,就通过XIB文件创建. 2.创建视图的时候,视图控制器会调用lo ...

  4. AHM ---301重定向

    使用amh.conf 或重新创建一个test.conf配置文件 .保存目录 /usr/local/nginx/conf/rewrite 例如跳到 www.shuaixingkeji.com if ($ ...

  5. 【java设计模式】之 单例(Singleton)模式

    1. 单例模式的定义 单例模式(Singleton Pattern)是一个比較简单的模式.其原始定义例如以下:Ensure a class has only one instance, and pro ...

  6. Win7下更改iTunes备份路径最便捷的方法

    ① 先删除C:\Users\你的用户名\AppData\Roaming\Apple Computer里的 MobileSync文件夹(首次安装iTunes要先运行一次itunes,才有这个文件夹,如果 ...

  7. 多线程-Thread,Runnable,Callable,Future,RunnableFuture,FutureTask

    类图: 先看各自的源码: public interface Runnable { public abstract void run(); } public class Thread implement ...

  8. git 删除github上的文件

    硬盘删除文件后,执行$ git status   会提示你仍然需要$ git rm <文件>   此时如果是要删除大批量文件,这么一个一个命令下去不得累死人啊   其实可以这样(不管之前有 ...

  9. makefile之call函数

    call函数是唯一一个可以创建定制化参数函数的引用函数. 支持对自定义函数的引用; 支持将一个变量定义为一个复杂的表达式,用call函数根据不同的参数对它进行展开来获取不同的结果; 函数语法: $(c ...

  10. [转]RPC、CORBA、WebService之区别

    RPC是由Sun发明的远程过程调用协议,是第一种真正的分布式应用模型.Windows上使用的R PC是DCERPC的扩展.严格地说,RPC是一种逻辑上的协议,它可以使用Socket.Named Pip ...