GO语言核心30讲 进阶技术 (第一部分)

 原站地址:Go语言核心36讲_Golang_Go语言-极客时间

一、数组和切片

1. 两者最大的不同:数组的长度是固定的,而切片的长度是可变的。

2. 可以把切片看成是对数组的一层封装,因为每个切片的底层数据结构中,一定会包含一个数组。 切片也可以被看作是对底层数组的某个连续片段的引用(窗口)。

3. go语言不存在传值或传引用两种区分。 只要传递的是引用类型的,就是“传引用”。如果传递的是值类型的,就是“传值”。   切片属于引用类型,数组属于值类型。

4. 内建函数 len()计算长度,cap()计算容量。

例子:  s1是切片,底层数组是8个元素。 s2 := s1[3:6]

len(s2) = 6-3, 即 结束索引 减去 起始索引

cap(s2) = 8-3,即 底层数组长度 减去  起始索引 , 从起始索引位置向右扩展到最末端

5. 切片容量的增长逻辑:

(1) 一般情况下,新切片的容量将会是原切片容量的 2 倍。

(2) 如果新长度比原容量的 2 倍还要大,那么新容量就会以新长度为基准。

(3) 如果原长度大于等于1024,会以原容量的1.25倍作为基准,一直扩展到满足扩容需求。

6. 切片的底层数组在扩容时不会被替换。 扩容时是使用了新的切片和新的底层数组。 旧切片不变。

二、container包中的容器:List 和 Ring

1. List 容器,是一个双向链表,所以它支持下面的方法:

(1) 把内部元素移动到链表头部或尾部,或移动到另一个元素的前面或后面

(2) 插入新元素到链表头部或尾部,或一个元素的前面或后面

(3) 如果自己生成元素,直接传给链表的方法做 移动操作,链表不会接受。因为可以根据前后元素的指针数据做合法性判定。

2. List 支持开箱即用。经过声明的List变量 是一个长度为0的链表,是一个空壳,但可以直接使用。 使用之后再做初始化。这种延迟初始化可以分散初始化带来的计算量压力。

3. List内部就是一个循环链表。它的根元素不持有实际的元素值,但连接了这个循环链表的首尾两端。

4. List 和 Ring 的区别

(1) List 和 Ring 都是循环链表

(2) List 可以添加和删除元素, Ring不可以。Ring要添加元素,需要重建一个新的Ring.

(3) Ring的数据结构仅由它自身即可代表,而List则需要由它以及Element类型联合表示。

三、字典的操作和约束

1. 哈希表查找某个 键值对应的元素值 的过程:

(1) 用哈希函数把键值转换为哈希值。 哈希值是一个无符号的整数

(2) 哈希表持有一定数量的桶(bucket),这些哈希桶储存其所属的一定数量 键-元素对。

(3) 哈希表用这个键的哈希值去定位一个哈希桶,然后在这个哈希桶中查找这个键-元素对。

2.  Map的键类型必须支持操作符 == 和 != 。 函数、字典和切片类型的值并不支持判等操作,所以他们不能作为键。

     如果键的类型是接口类型,而且实际类型也是上述三种类型,在程序运行过程中会引发 panic。

     如果键的类型是自定义结构体,而且包含上述三种类型,也是会panic

3. 键的数据类型,优先选用数值和指针类型。

    求哈希和判等操作的速度越快,对应的类型就越适合作为键类型。

    宽度越小、长度越短,求哈希值的速度越快。

4. 在值为nil的字典上执行读和写操作会成功吗?

(1) 仅声明而不初始化 字典变量,它的值会是nil。

(2) 往nil字段添加删除元素值,会panic

(3) 其他nil字典上的任何操作,包括获取元素值,都不会panic

四、通道的基本操作

1.  通道相当于一个先进先出队列,先被发送到通道的元素值,一定会先被接收。

2.  声明并初始化通道: ch1 := make(chan int, 3)     元素类型为int、容量为3

     往通道发送数据: ch1 <- 1

     从通道接收数据: data := <- ch1

3. 通道的三个特性:

(1) 发送操作之间,接收操作之间是互斥的。即多个goroutine要同时发通道发送数据时,只有一个能起作用。  对于同一个数据而言, 发送和接收两个操作也是互斥的。

(2) 发送和接收时,对数据的处理是不可分割的。即 只会是没发送或发送完,不会是发送了一半。

在通道中的数据,是被复制的一个副本。

(3) 发送和接收操作在完成之前, goroutine会被阻塞。包含复制、放置、删除三个步骤。如此阻塞是为了保证数据的安全和完整性。

4. 发送和接收是,触发阻塞状态的几种情况:

(1) 非缓冲通道,一执行就会阻塞

(2) 带缓冲的通道,缓冲区满了时发送操作会阻塞,缓冲区空了是接收操作会阻塞。

(3) 值为nil的通道,执行操作时会立刻阻塞。 不要忘记初始化通道。

5. 会引发panic的情况

(1) 向已经关闭的通道发送数据会panic。 但是接收数据的话不会。

(2) 试图关闭一个已经关闭的通道,会panic

6. 关闭通道,要交给发送方来做。

    因为即使通道已经关闭,接收方也能成功完成接收操作 (第二个结果值是true)。如果根据这个结果值来判断是否要做关闭操作的话,会引发重复关闭通道,导致panic。  所以应该让发送方根据发送逻辑来判定是否要关闭通道。

五、通道的高级玩法

1. 创建一个通道: ch := make(chan int, 1)

    创建单向只发通道: ch := make(chan <- int, 1)

    创建单向只收通道: ch := make( <- chan int, 1)

2. 单向通道的用途是约束局部代码的行为。某部分代码值能发送,某部分代码值能接收。

3. 只发通道应用: 只发通道作为参数传入

func SendInt(ch chan<- int) {ch <- rand.Intn(1000)
}

    外部函数向上面这个函数传参时,可以传入一个双向通道,GO语言会自动把双向通道转换为单向通道。

4. 只收通道应用: 只收通道作为结果返回

func getIntChan() <-chan int {num := 5ch := make(chan int, num)for i := 0; i < num; i++ {ch <- i}close(ch)return ch
}

   注意,这里函数内部已经把通道给关闭了

5. 用 for range 接收通道数据

intChan2 := getIntChan()
for elem := range intChan2 {fmt.Printf("The element in intChan2: %v\n", elem)
}

  for 循环会一直从通道接收数据。 接收完之后,如果通道没关闭就会阻塞,如果关闭了就会直接执行退出for循环。

6. select语句与通道联用

// 准备好几个通道。
intChannels := [2]chan int{make(chan int, 1),make(chan int, 1),
}
// 随机选择一个通道,并向它发送元素值。
index := rand.Intn(2)
fmt.Printf("The index: %d\n", index)
intChannels[index] <- index
// 哪一个通道中有可取的元素值,哪个对应的分支就会被执行。
select {
case <-intChannels[0]:fmt.Println("The first candidate case is selected.")
case <-intChannels[1]:fmt.Println("The second candidate case is selected.")
default:fmt.Println("No candidate case is selected!")
}

(1) select语句只能与通道联用

(2) 加入了 default 分支后,当其他分支都出现阻塞,select语句就会进入default分支。

(3) 没有加入default 分支的话,其他分支都出现阻塞,select语句就会阻塞。

(4) select只会对分支的通道求值操作一次,如果要反复操作通道的话,需要加for循环。但要注意,default里的代码执行break,只会结束掉select语句,不会结束掉for语句。

7. select 的分支选择规则都有哪些?

(1) case 右边的表达式,可以是通道接收操作,也可以是发送操作。

(2) case 右边的表达式,可以有多个接收操作。

(3) select语句的执行是先全部分支case求值,完毕后再选择其中一个分支。

(4) case 求值顺序是从上至下,从左至右。

(5) 多个case满足条件的话,select语句会随机选择一个分支去执行。

(6) default 分支只有在无候选分支可选时才会被执行,与default分支是位置无关

六、使用函数的正确姿势

1. 什么是高阶函数?  (函数式编程的重要概念) 满足以下两条件之一:

(1) 接受其他函数作为参数输入

(2) 把其他函数作为结果返回

2. 如何实现高阶函数? 下面以 函数作为参数输入 做例子。

(1) 声明一个名叫operate的函数类型

type operate func(x, y int) int

(2) 实现这个函数(低阶),签名与上面声明的一样。并赋值给函数变量 op

op := func(x, y int) int {return x + y
}

(3) 实现高阶函数,把低阶函数 operate 作为参数输入。 并调用执行这个函数,op()

func calculate(x int, y int, op operate) (int, error) {res := op(x, y)return res , nil
}

    这个 calculate 就是高阶函数,提供给外部调用。

3. 那如何把 函数作为结果返回

func genCalculator() calculateFunc {f := func(x int, y int) (int, error) {return x + y}return f, nil
}

     genCalculator 内部实现了一个匿名函数,作为结果值返回

4. 什么是自由变量?作用是什么?

    自由变量 是一个低阶函数,这个低阶函数是从外部传入的,如何实现由外部决定。

    作用是 动态地生成部分程序逻辑, 再根据需要生成功能不同的函数。

5. 传入函数的那些参数值,被修改后,原值会发生变化吗?

    值类型比如数组的话,不会。

    引用类型比如切片、字典、通道的话,会。

七、结构体及其方法的使用法门

1. 什么叫嵌入字段?

// Category 代表动物分类学中的基本分类法。
type Category struct {family string // 科。species string // 种。
}func (ac Category) String() string {return fmt.Sprintf("%s%s", ac.family, ac.species)
}type Animal struct {name string // 名字。Category    // 分类。
}

    上面结构体 Animal 的 Category 字段就是嵌入字段,也叫匿名字段,没有声明名称,它既是类型也是名称

2.  怎样调用嵌入字段的方法?

    通过类型变量的名称 Category 后跟 “.”, 这样: 

animal := Animal{name: "Shorthair",
}
animal.Category.String()

3.  嵌入字段的方法 会被无条件地 合并进 被嵌入类型的方法集合中.

    比如上面 Animal类型变量animal可以直接使用Category变量的方法: animal.String()

4. 如果 嵌入结构体(Category) 和 被嵌入结构体(Animal) 存在相同的方法名字,那么 嵌入结构体(Category) 的方法会被屏蔽。 即外层优先。

5. GO语言没有继承,但是用 嵌入的方式实现了类型之间的组合。(但和继承有差别,且更优)

6. GO的组合,和继承的区别:

(1) 组合 不需要 显式地声明某个类型继承了另一个类型,只需要把类型当做字段嵌入进来。

(2) 组合 可以通过嵌入多个字段来实现功能强大的类型,却不会有多重继承那样复杂的层次结构。

7. 接口类型之间也可以组合,而且更加常见

8. 什么叫 接受者类型 和 接受者名称 ? 如下代码

func (cat *Cat) SetName(name string) {cat.name = name
}

   *Cat 叫 接收者类型, cat 叫 接收者名称

9. 什么叫指针方法?  就是 接收者类型是指针类型的方法。  不是指针类型的话,叫做 值方法。 

10. 值方法和指针方法的不同点:

(1) 值方法的修改 不会修改 接受者的原值; 但是指针方法的修改 会改变原值

(2) 值方法集合 和 指针方法集合 两者是不同的。但指针方法集合 包含了 值方法集合

(3) 严格来讲,基本类型的值上只能调用它的值方法。但是,Go 语言会自动转译,使得值上也能调用到指针方法。

(4) 如果基本类型和指针类型的方法集合不同,那么它们实现的接口类型的数量也会有差异。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/6213.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4.2_文本处理工具

## 1.grep ## grep [Globally search a Regular Expression and Print] &#xff08;1&#xff09;grep 格式 ##grep 格式## grep 匹配条件 处理文件 grep root passwd #过滤root关键字 grep -E egrep #扩展搜索 grep -i root passwd ##忽…

【leetcode】优先队列题目总结

优先队列的底层是最大堆或最小堆 priority_queue<Type, Container, Functional>; Type是要存放的数据类型Container是实现底层堆的容器,必须是数组实现的容器,如vector、dequeFunctional是比较方式/比较函数/优先级priority_queue<Type>; 此时默认的容器是vect…

深度学习之基于Vgg16卷积神经网络印度交警手势识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 随着智能交通系统的发展&#xff0c;手势识别技术成为了一个关键组成部分&#xff0c;特别是在交通管…

基于SSM SpringBoot vue宾馆网上预订综合业务服务系统

基于SSM SpringBoot vue宾馆网上预订综合业务服务系统 系统功能 首页 图片轮播 宾馆信息 饮食美食 休闲娱乐 新闻资讯 论坛 留言板 登录注册 个人中心 后台管理 登录注册 个人中心 用户管理 客房登记管理 客房调整管理 休闲娱乐管理 类型信息管理 论坛管理 系统管理 新闻资讯…

ArrayList还是LinkedList?

引言 集合作为一种存储数据的容器&#xff0c;是我们日常开发中使用最频繁的对象类型之一。JDK为开发者提供了一系列的集合类型&#xff0c;这些集合类型使用不同的数据结构来实现。因此&#xff0c;不同的集合类型&#xff0c;使用场景也不同。 很多同学在面试的时候&#x…

多列列表OCX控件

VB6写的一个多列列表OCX控件源码&#xff0c;核心就是利用数组划分成多列数据&#xff0c;可装载亿条数据以上&#xff0c;控件引用了四个PictureBox控件分别作为:索引号显示&#xff0c;列表&#xff0c;垂直滚动条和横向滚动条&#xff0c;基本实现列表的添加、修改和删除等功…

文本嵌入的隐私风险:从嵌入向量重建原始文本的探索

随着大型语言模型&#xff08;LLMs&#xff09;的广泛应用&#xff0c;文本嵌入技术在语义相似性编码、搜索、聚类和分类等方面发挥着重要作用。然而&#xff0c;文本嵌入所蕴含的隐私风险尚未得到充分探讨。研究提出了一种控制生成的方法&#xff0c;通过迭代修正和重新嵌入文…

TCP 协议

TCP协议段格式 源/目的端口号&#xff1a;表示数据是从哪个进程来&#xff0c;到哪个进程去。 序号&#xff1a;发送数据的序号。 确认序号&#xff1a;应答报文的序号&#xff0c;用来回复发送方的。 4 位首部长度&#xff1a;一个 TCP 报头&#xff0c;长度是可变的&#xff…

Spring Boot使用Logback将某些日志输出到单独的文件

缘起 重构了某个接口&#xff0c;想监控下新接口各个处理过程的时间&#xff0c;从而评估和监控日常性能。监控使用Spring自带的StopWatch&#xff0c;日志使用Logback 配置 先拷贝一份infoAppender配置过来改个名 <!-- 监控日志 --><appender name"monitorAp…

简化Transformer模型,以更少的参数实现更快的训练速度

在深度学习领域&#xff0c;Transformer模型因其卓越的性能而广受欢迎&#xff0c;但其复杂的架构也带来了训练时间长和参数数量多的挑战。ETH Zurich的研究人员Bobby He和Thomas Hofmann在最新研究中提出了一种简化的Transformer模型&#xff0c;通过移除一些非必要的组件&…

【VueUse】超越基本功能的高级 Vue 元素操作

在vue开发中我们经常需要操作DOM元素&#xff0c;从简单的添加类到动态创建元素&#xff0c;这些操作都是不可避免的。而在VueUse库中&#xff0c;Elements相关API函数为我们提供了一系列强大而灵活的工具&#xff0c;帮助我们更轻松地处理DOM元素。无论是优雅地处理元素、动态…

JavaEE技术之MySql高级(索引、索引优化、sql实战、View视图、Mysql日志和锁、多版本并发控制)

文章目录 1. MySQL简介2. MySQL安装2.1 MySQL8新特性2.2 安装MySQL2.2.1 在docker中创建并启动MySQL容器&#xff1a;2.2.2 修改mysql密码2.2.3 重启mysql容器2.2.4 常见问题解决 2.3 字符集问题2.4 远程访问MySQL(用户与权限管理)2.4.0 远程连接问题1、防火墙2、账号不支持远程…

从永远到永远-和弦-挂留和弦

挂留和弦 1.概念2.指型1.Xsus2和弦2.Xsus4和弦 3.应用 1.概念 该篇说下和弦中的“渣男”、“绿茶”&#xff0c;挂留和弦。 挂留&#xff08;suspended&#xff09;和弦是将三和弦的三音替换成大二度或纯四度音形成的&#xff0c;包括挂留二和弦、挂留四和弦两种。 三音是一个…

手撕vector的模拟实现

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary_walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

JDK14特性

JDK14 1 概述2 语法层面的变化1_instanceof的模式匹配(预览)2_switch表达式(标准)3_文本块改进(第二次预览)4_Records 记录类型(预览 JEP359) 3 API层面的变化4 关于GC1_G1的NUMA内存分配优化2_弃用SerialCMS,ParNewSerial Old3_删除CMS4_ZGC on macOS and Windows 4 其他变化1…

自学Redis7入门篇一

自学Redis7入门篇一 Redis概述一、Redis是什么&#xff1f;二、Redis能干什么&#xff1f;三、去哪里下四、Redis安装配置五、Redis 10数据类型1.字符串(String)2.列表(List)3.哈希表(Hash)4.集合(Set)5.有序集合(ZSet)6.地理空间(GEO)7.基数统计(HyperLogLog)8.位图(bitmap)9.…

streampetr原版网络nuscenes数据pkl文件中的各字段含义

streampetr原版网络nuscenes数据pkl文件中的各字段含义 每帧数据都包含下列的信息 "token": 该帧数据的标识&#xff0c;具有唯一性 "prev": 该帧数据上一帧数据的token&#xff0c;如果没有就为"" "next": 该帧数据下一帧数据的toke…

计算机毕业设计PHP+vue体检预约管理系统d1yu38

防止在使用不同数据库时&#xff0c;由于底层数据库技术不同造成接口程序紊乱的问题。通过本次系统设计可以提高自己的编程能力&#xff0c;强化对所学知识的理解和运用 本系统是一个服务于医院先关内容的网站&#xff0c;在用户打开网站的第一眼就要明白网站开发的目的&#x…

[报错解决]Starting zookeeper ... already running as process 15400.

报错一 ZooKeeper JMX enabled by default Using config: /usr/local/zookeeper-cluster/zookeeper-1/bin/../conf/zoo.cfg Starting zookeeper ... already running as process 15400.解决 netstat -anp | grep 端口号 # 如果集群没有启动&#xff0c;那么该端口不应该被占…

windows qt sdk 安装

在Windows上安装Qt SDK的步骤如下&#xff1a; 下载Qt SDK安装包&#xff1a; 打开Qt资源下载网站&#xff0c;如http://download.qt.io/。 选择适合您Windows版本和需求的Qt SDK版本进行下载。通常建议选择稳定版本&#xff0c;并确认是否包含所需的组件&#xff0c;如Qt Cre…