zoukankan      html  css  js  c++  java
  • [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. 如果被用到了,会有编译错误。

  • 相关阅读:
    前端与算法 leetcode 344. 反转字符串
    JavaScript闭包使用姿势指南
    前端与算法 leetcode 48. 旋转图像
    前端与算法 leetcode 36. 有效的数独
    前端与算法 leetcode 1. 两数之和
    前端与算法 leetcode 283. 移动零
    前端与编译原理 用js去运行js代码 js2run
    前端与算法 leetcode 66. 加一
    前端与算法 leetcode 350. 两个数组的交集 II
    前端与算法 leetcode 26. 删除排序数组中的重复项
  • 原文地址:https://www.cnblogs.com/lemonbar/p/3928357.html
Copyright © 2011-2022 走看看