乐趣区

关于golang:Go-语言第一课基础篇2

构造体
咱们编写程序的目标就是与真实世界交互,解决真实世界的问题,帮忙真实世界进步运行效率与改善运行品质。所以咱们就须要对真实世界事物体的重要属性进行提炼,并映射到程序世界中,这就是所谓的对真实世界的形象。

实质上雷同的两个类型,它们的变量能够通过显式转型进行互相赋值,相同,如果实质上是不同的两个类型,它们的变量间连显式转型都不可能,更不要说互相赋值了.

咱们还能够用空标识符“_”作为构造体类型定义中的字段名称。这样以空标识符为名称的
字段,不能被内部包援用,甚至无奈被构造体所在的包应用。

第一种:定义一个空构造体。
咱们能够定义一个空构造体,也就是没有蕴含任何字段的构造体类型.

type Empty struct{} // Empty 是一个不蕴含任何字段的空构造体类型

空构造体类型变量的内存占用为 0。基于空构造体类型内存零开销这样的个性,咱们在日常 Go 开发中会常常应用空构造体类型元素,作为一种“事件”信息进行 Goroutine 之间的通信。

var c = make(chan Empty)   // 申明一个元素类型为 Empty 的 channel
c<-Empty{}                // 向 channel 写入一个“事件”

第二种状况:应用其余构造体作为自定义构造体中字段的类型
这种形式定义的构造体字段,咱们叫做嵌入字段(Embedded Field)。咱们也能够将这种字段称为匿名字段,或者把类型名看作是这个字段的名字.

构造体变量的申明与初始化:
1. 零值初始化说的是应用构造体的零值作为它的初始值.“零值”这个术语重复呈现过屡次,它指的是一个类型的默认值。对于 Go 原生类型来说,这个默认值也称为零值。Go 构造体类型由若干个字段组成,当这个构造体类型变量的各个字段的值都是零值时,咱们就说这个构造体类型变量处于零值状态。

在 Go 语言规范库和运行时的代码中,有很多践行“零值可用”理念的好例子,最典型的莫过于 sync 包的 Mutex 类型了。

2. 对构造体变量进行显式初始化的形式,就是按程序顺次给每个构造体字段进行赋值

type Book struct {
Title string // 书名
Pages int // 书的页数
Indexes map[string]int // 书的索引
} v
t := T{}

像这类通过专用构造函数进行构造体类型变量创立、初始化的例子还有很多,咱们能够总结一下,它们的专用构造函数大多都合乎这种模式。

func NewT(field1, field2, ...) *T {... ...}

NewT 是构造体类型 T 的专用构造函数,它的参数列表中的参数通常与 T 定义中的导出字段绝对应,返回值则是一个 T 指针类型的变量。T 的非导出字段在 NewT 外部进行初始化,一些须要简单初始化逻辑的字段也会在 NewT 外部实现初始化。这样,咱们只有调用 NewT 函数就能够失去一个可用的 T 指针类型变量了。

构造体类型的内存布局
Go 编译器为什么要在构造体的字段间插入“填充物”呢?这其实是内存对齐的要求。所谓内存对齐,指的就是各种内存对象的内存地址不是随便确定的,必须满足特定要求。

对于各种根本数据类型来说,它的变量的内存地址值必须是其类型自身大小的整数倍,比方,一个 int64 类型的变量的内存地址,应该能被 int64 类型本身的大小,也就是 8 整除;一个 uint16 类型的变量的内存地址,应该能被 uint16 类型本身的大小,也就是 2 整除。

控制结构:
程序 = 数据结构 + 算法

算法是对真实世界运作法则的形象,是解决真实世界中问题的步骤。在计算机世界中,再简单的算法都能够通过 程序、分支和循环 这三种根本的控制结构结构进去。

操作符的优先级

Go 社区把这种 if 语句的应用形式称
为 if 语句的“高兴门路(Happy Path)”准则,所谓“高兴门路”也就是胜利逻辑的代码
执行门路,它的特点是这样的:

Go 社区举荐 Gopher 们在应用 if 语句时尽量合乎这些准则,如果你的函数实现代码不符
合“高兴门路”准则,你能够按上面步骤进行重构:

  1. 仅应用单分支控制结构;
  2. 当布尔表达式求值为 false 时,也就是呈现谬误时,在单分支中疾速返回;
  3. 失常逻辑在代码布局上始终“靠左”,这样读者能够从上到下一眼看到该函数失常逻辑的全貌;
  4. 函数执行到最初一行代表一种胜利状态。

for 循环语句的经典模式

var sum int
for i := 0; i < 10; i++ {sum += i}p
rintln(sum)

当 for 循环语句的循环判断条件表达式的求值后果始终为 true 时,咱们就能够将它省略掉了

for range 循环模式

for i, v := range sl {fmt.Printf("sl[%d] = %d\n", i, v)
}

Switch 语句:

switch initStmt; expr {
case expr1:
// 执行分支 1
case expr2:
// 执行分支 2
case expr3_1, expr3_2, expr3_3:
// 执行分支 3
case expr4:
// 执行分支 4
... ...
case exprN:
// 执行分支 N
default:
// 执行默认分支
}

switch 关键字开始,它的前面通常接着一个表达式(expr),这句中的 initStmt 是一个可选的组成部分

无论 default 分支呈现在什么地位,它都只会在所有 case 都没有匹配上的状况下才会被执行的.

Go 语言中的 Swith 语句就修复了 C 语言的这个缺点,勾销了默认执行下一个 case 代码逻辑的“非常规”语义,每个 case 对应的分支代码执行完后就完结 switch 语句

type switch

func main() {var x interface{} = 13
switch x.(type) {
case nil:
println("x is nil")
case int:
println("the type of x is int")
case string:
println("the type of x is string")
case bool:
println("the type of x is string")
default:
println("don't support the type")
}
}

Go 语言标准中明确规定,不带 label 的 break 语句中断执行并跳出的,是同一函数内 break 语句所在的最内层的 for、switch 或 select

咱们定义了一个 label:loop,这个 label 附在 for 循环的里面,指代 for 循环的执行。当代码执行到“break loop”时,程序将进行 label loop 所指代的 for 循环的执行

函数:
在 Go 语言中,函数是惟一一种基于特定输出,实现特定工作并可返回工作执行后果的代码块(Go 语言中的办法实质上也是函数).

函数字面值由函数类型与函数体组成,它特地像一个没有函数名的函数申明,因而咱们也叫它匿名函数

闭包实质上就是一个匿名函数或叫函数字面值,它们能够援用它的包裹函数,也就是创立它们的函数中定义的变量。而后,这些变量在包裹函数和匿名函数之间共享,只有闭包能够被拜访,这些共享的变量就会持续存在。

Error
Go 语言的设计者显然也想到了这一点,他们在规范库中提供了两种不便 Go 开发者结构谬误值的办法:errors.New 和 fmt.Errorf errors.Is 和 errors.As 函数

panic
panic 指的是 Go 程序在运行时呈现的一个异常情况。如果异样呈现了,但没有被捕捉并复原,Go 程序的执行就会被终止,即使出现异常的地位不在主 Goroutine 中也会这样。在 Go 中,panic 次要有两类起源,一类是来自 Go 运行时,另一类则是 Go 开发人员通过 panic 函数被动触发的。无论是哪种,一旦 panic 被触发,后续 Go 程序的执行过程都是一样的,这个过程被 Go 语言称为 panicking

Go 也提供了捕获 panic 并恢复程序失常执行秩序的办法,咱们能够通过 recover 函数来实现这一点

办法:
在 receiver 局部申明的参数,Go 称之为 receiver 参数,这个 receiver 参数也是办法与类型之间的纽带,也是办法与函数的最大不同.

Go 中的办法必须是归属于一个类型的,而 receiver 参数的类型就是这个办法归属的类型,或者说这个办法就是这个类型的一个办法.

Go 语言对 receiver 参数的基类型也有束缚,那就是 receiver 参数的基类型自身不能为指针类型或接口类型

Go 语言中的办法的实质就是,一个以办法的 receiver 参数作为第一个参数的一般函数。

办法汇合决定接口实现的含意就是:如果某类型 T 的办法汇合与某接口类型的办法汇合雷同,或者类型 T 的办法汇合是接口类型 I 办法汇合的超集,那么咱们就说这个类型 T 实现了接口 I。或者说,办法汇合这个概念在 Go 语言中的主要用途,就是用来判断某个类型是否实现了某个接口。


Go 组合设计哲学

什么是类型嵌入
类型嵌入指的就是在一个类型的定义中嵌入了其余类型。Go 语言反对两种类型嵌入,别离是接口类型的类型嵌入和构造体类型的类型嵌入。

接口类型的类型嵌入
这种在一个接口类型(I)定义中,嵌入另外一个接口类型(E)的形式,就是咱们说的接口类型的类型嵌入.

接口类型嵌入的语义就是新接口类型(如接口类型 I)将嵌入的接口类型(如接口类型 E)的办法汇合,并入到本人的办法汇合中.

咱们在 Go 规范库中能够看到很多这种组合形式的利用,最常见的莫过于 io 包中一系列接
口的定义了。比方,io 包的 ReadWriter、ReadWriteCloser 等接口类型就是通过嵌 Reader、Writer 或 Closer 三个根本的接口类型组合而成的。

type ReadWriter interface {
    Reader
    Writer
}

type ReadCloser interface {
    Reader
    Closer
}

type WriteCloser interface {
    Writer
    Closer
}

type ReadWriteCloser interface {
    Reader
    Writer
    Closer
}

构造体类型的类型嵌入:

以某个类型名、类型的指针类型名或接口类型名,间接作为构造体字段的形式就叫做构造体的类型嵌入,这些字段也被叫做嵌入字段(Embedded Field)。

Go 中的“继承”理论是一种组合,
更具体点是组合思维下代理(delegate)模式的使用,也就是新类型代理了其嵌入类型的所有办法。当外界调用新类型的办法时,Go 编译器会首先查找新类型是否实现了这个办法,如果没有,就会将调用委派给其外部实现了这个办法的嵌入类型的实例去执行,你肯定要了解这个原理。

Go 1.17 版本在语法个性方面仅仅做了一处加强,那就是 反对切片转换为数组指针

在 Go 1.17 版本中,go get 曾经不再被用来装置某个命令的可执行文件了.

咱们须要应用 go install 来装置,并且应用 go install 装置时还要用 @vx.y.z 明确要装置的命令的二进制文件的版本,或者是应用 @latest 来装置最新版本.

Go 学习材料:
Go 官网文档:

Go 语言标准
Go module 参考文档
Go 命令参考手册
Effective Go
Go 规范库包参考手册
Go 常见问答

Go 语言官博,Go 外围团队对于 Go 语言的权威公布渠道;
Go 语言之父 Rob Pike 的集体博客;
Go 外围团队技术负责人 Russ Cox 的集体博客;
Go 外围开发者 Josh Bleecher Snyder 的集体博客;
Go 外围团队前成员 Jaana Dogan 的集体博客;
Go 鼓吹者 Dave Cheney 的集体博客;
Go 语言培训机构 Ardan Labs 的博客;

GoCN 社区;
Go 语言百科全书:由欧长坤保护的 Go 语言百科全书网站。

GopherChina 技术大会,
GopherCon 技术大会
Go 官网的技术演讲归档,
Go 语言爱好者周刊
Gopher 日报

退出移动版