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

   2023-02-09 学习力0
核心提示:这两天在看reflect这个包在Docker中的使用时,遇到了各种问题,最后虽然知道怎么用了。但是对于这块的原理还不是太懂,于是把"THE WAY TO GO"中关键的几章看了下。继续坚持往下写,争取能说明白。源码还是先看Docker中源码, docker/api/client/cli.gotype Doc

这两天在看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. 如果被用到了,会有编译错误。

 

 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • intellij idea go go go!
    安装如下:1. intellij idea2. jdk-8u31-windows-x643.1. scala:Scala是一门多范式的编程语言,一种类似java的编程语言[1]  ,设计初衷是实现可伸缩的语言[2]  、并集成面向对象编程和函数式编程的各种特性。 2.IdeaVimEmulates Vim editorVim是一个类似
    03-08
  • 用 VSCode 搭建 Go 语言开发环境
    用 VSCode 搭建 Go 语言开发环境
    介绍这是来自 Funai Research Institute Digital 的 osw。由于我决定使用 Go 语言进行工作,所以我会在学习时将其记录在备忘录中。如果您可以参考,我将不胜感激。目标听众从现在开始学习 Go 语言的人我正在考虑使用 VSCode本次使用的环境这次,我们将基于以
    03-08
  • Go语言使用goroutine及通道实现并发详解
    Go语言使用goroutine及通道实现并发详解
    目录使用通道接收数据阻塞接收数据非阻塞接收数据接收任意数据,忽略掉接收的数据循环接收数据使用通道接收数据在上一篇文章中介绍了通道以及使用通道发送数据,本篇接着了解通道的基本内容,如何使用通道接收数据;通道的接收同样使用"-"操作符;使用通道接
  • Go 数据结构之堆排序示例详解
    Go 数据结构之堆排序示例详解
    目录堆排序堆排序过程动画显示开始堆排序代码实现总结堆排序堆排序是一种树形选择排序算法。简单选择排序算法每次选择一个关键字最小的记录需要 O(n) 的时间,而堆排序选择一个关键字最小的记录需要 O(nlogn)的时间。堆可以看作一棵完全二叉树的顺序存储结构
  • Go语言数据结构之希尔排序示例详解 go语言堆排序
    Go语言数据结构之希尔排序示例详解 go语言堆排
    目录希尔排序算法思想图解算法Go 代码实现:总结希尔排序在插入排序中,在待排序序列的记录个数比较少,而且基本有序,则排序的效率较高。1959 年,Donald Shell 从“减少记录个数” 和 “基本有序” 两个方面对直接插入排序进行了改进,提出了希尔排序
  • 【每天自动更新】Go增强月-分享你的开发必备知识-LGTM排行榜!
    【每天自动更新】Go增强月-分享你的开发必备知
    这篇文章是“Go增强月——让我们分享你需要知道的发展知识——”本文支持主题。我们将使用 Qiita API v2 来收集似乎在参与“Go 增强月-让我们分享您需要了解的开发知识-”的文章。我将在收集的文章组(数据)上尝试这个和那个。按 LGTM 编号对文章进行排序投
  • Go REFLECT Library反射类型详解
    Go REFLECT Library反射类型详解
    目录一、反射概述二、反射类型对象基本数类型的 反射类型对象引用数据类型的 反射类型对象结构体的 反射类型对象指针的 反射类型对象一、反射概述反射是指程序在运行期间对程序本身进行访问和修改的能力。程序在编译过程中变量会被转换为内存地址,变量名不会
  • Go-ethereum 解析ethersjs中产生的签名信息思路详解
    Go-ethereum 解析ethersjs中产生的签名信息思
    目录Go-ethereum 解析ethersjs中产生的签名信息1. ethers 消息签名1.1 ethers 对签名消息进行解析2. Golang 签名解析3. 总结Go-ethereum 解析ethersjs中产生的签名信息在签名验证的过程中,我们判断签名正确的前提是,签名解析后的公钥,和发起这次动作的人是
  • go并发编程sync.Cond使用场景及实现原理
    目录使用场景实现原理copyCheckerWaitSignalBroadcast使用场景sync.Cond是go标准库提供的一个条件变量,用于控制一组goroutine在满足特定条件下被唤醒。sync.Cond常用于一组goroutine等待,一个goroutine通知(事件发生)的场景。如果只有一个goroutine等待,
  • go 熔断原理分析与源码解读
    go 熔断原理分析与源码解读
    目录正文熔断原理熔断器实现hystrixBreaker和googlebreaker对比源码解读结束语正文熔断机制(Circuit Breaker)指的是在股票市场的交易时间中,当价格的波动幅度达到某一个限定的目标(熔断点)时,对其暂停交易一段时间的机制。此机制如同保险丝在电流过大时
点击排行