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 := 5
  ch := 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.mfbz.cn/a/609830.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ARM(2)ARMv8基础知识

目录 一、异常 1.1异常等级的定义 1.2异常的种类 1.2.1同步异常和异步异常 1.3改变异常等级 1.4异常后的处理 1.4.1异常处理相关寄存器 1.4.2系统调用 1.4.3对EL2/EL3的系统调用 1.4.4异常返回 1.4.5异常处理流程 二、安全状态 三、执行状态 本文介绍以下内容&…

KUKA机器人X11投入运行模式

KUKA机器人出厂时有个X11外部安全插头&#xff0c;外部急停和安全门就是从其中引出双回路接线。正常使用时需要将插头内部短接&#xff0c;不短接则会出现外部安全停止等报警信息&#xff0c;导致机器人无法上使能&#xff0c;不能转动。 通过设置【投入运行模式】可以暂时屏蔽…

Linux 操作系统TCP、UDP

1、TCP服务器编写流程 头文件&#xff1a; #include <sys/socket.h> 1.1 创建套接字 函数原型&#xff1a; int socket(int domain, int type, int protocol); 参数&#xff1a; domain: 网域 AF_INET &#xff1a; IPv4 AF_INET6 &a…

大数据面试题 —— 数据库

目录 关系型数据库与非关系型数据库的区别数据库三范式MySQL中 drop、delete、truncate的区别MySQL中 char和 varchar 的区别MySQL中inner join、left join、right join以及full join的区别MySQL中 having 和 where 的区别count(*)、count(1)、count(列名)的区别MySQL中视图和表…

【C++】-类模板-002

1创建类模板 &#xff08;1&#xff09;新建工程 &#xff08;2&#xff09; &#xff08;3&#xff09; &#xff08;4&#xff09; &#xff08;5&#xff09;模板运行结果 2【UI】设计器 &#xff08;1&#xff09;跳转到【UI】设计器 &#xff08;2&#xff09;添加…

神经网络中的归一化

我们今天介绍一下神经网络中的归一化方法~ 之前学到的机器学习中的归一化是将数据缩放到特定范围内&#xff0c;以消除不同特征之间的量纲和取值范围差异。通过将原始数据缩放到一个特定的范围内&#xff0c;比如[0,1]或者[-1,1]&#xff0c;来消除不同特征之间的量纲和取值范围…

Ti雷达CFG阅读技巧

Ti雷达CFG阅读技巧 使用TI雷达测量数据前&#xff0c;需要考虑不同的设计参数之间的区别&#xff0c;虽然Ti雷达的说明文档非常清晰&#xff0c;直接查询mmwave_sdk_user_guide文档就可以了&#xff0c;但是用的多了&#xff0c;参数都知道可能是什么含义&#xff0c;来回查询…

Springboot集成Mybatispuls操作mysql数据库-04

MyBatis-Plus&#xff08;简称MP&#xff09;是一个MyBatis的增强工具&#xff0c;在MyBatis的基础上只做增强而不做改变。它支持所有MyBatis原生的特性&#xff0c;因此引入MyBatis-Plus不会对现有的MyBatis构架产生任何影响。MyBatis-Plus旨在简化开发、提高效率&#xff0c;…

商务分析方法与工具(七):Python的趣味快捷-异常处理结构

Tips&#xff1a;"分享是快乐的源泉&#x1f4a7;&#xff0c;在我的博客里&#xff0c;不仅有知识的海洋&#x1f30a;&#xff0c;还有满满的正能量加持&#x1f4aa;&#xff0c;快来和我一起分享这份快乐吧&#x1f60a;&#xff01; 喜欢我的博客的话&#xff0c;记得…

布局全球内容生态,酷开科技Coolita AIOS以硬核品质亮相

当前&#xff0c;全球产业链供应链格局持续重构&#xff0c;成为影响中国对外经济发展的重要因素。2024年4月15至5月5日&#xff0c;历史久、规模大、层次高&#xff0c;作为中国外贸风向标的第135届中国进出口商品交易会&#xff08;即广交会&#xff09;在美丽的广州隆重举行…

matlab打开文件对话框

在使用matlab GUI制作时&#xff0c;为了便于用户交互使用&#xff0c;经常设置文件打开对话框&#xff0c;让用户根据实际需要选择打开的文件。下面以打开一张图片为例&#xff0c;matlab代码如下&#xff1a; [temp_filepath,temp_filename]uigetfile(*.jpg,请选择要打开的图…

探秘Tailwind CSS:前端开发的加速器(TailwindCSS让CSS编写更简洁)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 Tailwind CSS 📒📝 快速体验📝 深入学习⚓️ 相关链接 ⚓️📖 介绍 📖 在这个快速迭代的互联网时代,前端开发效率和设计质量的双重要求,使得开发者们不断寻求更高效的工具和方法。今天,我们要介绍的是一个能够极大…

如何在Python中调用系统命令或执行外部程序?详细教程来了!

基本原理 在Python中执行程序或调用系统命令是一项非常实用的技能&#xff0c;这允许Python脚本与操作系统进行交互&#xff0c;执行各种外部程序。Python提供了多种方法来实现这一功能&#xff0c;包括os.system(), subprocess模块等。 示例代码 示例1&#xff1a;使用os.s…

LLM生态下爬虫程序的现状与未来

最近出现一批与LLM有关的新的爬虫框架&#xff0c;一类是为LLM提供内容抓取解析的&#xff0c;比如 Jina Reader 和 FireCrawl &#xff0c;可以将抓取的网页解析为markdown这样的对LLM友好的内容&#xff0c;例如markdown&#xff0c;这类本质上还是传统的爬虫解决方案。还有一…

[C++] const 成员函数

标题&#xff1a;[C] this指针 & const 成员函数 水墨不写bug 正文开始&#xff1a; 目录 &#xff08;一&#xff09;Cpp的面向对象编程 &#xff08;二&#xff09;this指针 &#xff08;三&#xff09;const修饰的成员函数 在正式讲解const修饰成员函数之前&#x…

在做题中学习(55):一维前缀和模板

【模板】前缀和_牛客题霸_牛客网 (nowcoder.com) 题目解释&#xff1a; 注意&#xff1a;下标从1开始的。 l 和 r就是对这n个整数去取一个区间&#xff0c;例如示例一&#xff1a; (1,2) 区间 就是算出1 2 4 中 1&#xff0c;2下标对应值的和&#xff0c;12 3 同理,(2,3) …

vscode正则匹配技巧

写正则表达式 下面是匹配加粗的单词或空格 \*\*[a-zA-Z\s]*\*\*vscode提取加粗的内容 altenter&#xff0c;再ctrlC复制选中的内容出来

前端 | iframe框架标签应用(三)| 点击指定部分,进行外部页面搜索,内置iframe返回搜索结果

文章目录 &#x1f4da;实现效果&#x1f4da;模块实现解析 &#x1f4da;实现效果 点击单词列表内的任意单词↓ 弹出对应单词的搜狗翻译搜索结果&#xff0c;点击关闭按钮关闭界面。 &#x1f4da;模块实现解析 在列表框搜索功能的基础上加一个click触发效果就好了&#xf…

网络安全在数字时代的重要性:以近期网络安全事件为镜

在当今这个信息化爆炸的时代&#xff0c;互联网如同一张无形的网&#xff0c;将我们的生活、工作、学习紧密相连。然而&#xff0c;这张网在带来便捷的同时&#xff0c;也暗藏着无数的安全隐患。近年来&#xff0c;网络安全事件频发&#xff0c;从个人隐私泄露到企业数据被盗&a…

网站未部署证书有何影响,如何解决?

如果您的网站没有ssl证书会有以下风险 1 浏览器标记为不安全 未安装证书的网站在访问时会有不安全的提示弹窗或者在网址栏直接显示不安全 2 影响企业信誉 当用户访问网站时看到不安全提示&#xff0c;会对网站的真实性和安全性产生怀疑&#xff0c;不敢轻易与该企业合作&…
最新文章