|
@@ -0,0 +1,150 @@
|
|
|
+# Go 系统概述
|
|
|
+
|
|
|
+## 基本类型
|
|
|
+
|
|
|
+![image-20220826155421304](system.assets/image-20220826155421304.png)
|
|
|
+
|
|
|
+## 组合类型
|
|
|
+
|
|
|
+数组长度固定、切片动态长度
|
|
|
+
|
|
|
+```go
|
|
|
+1| // 假设T为任意一个类型,Tkey为一个支持比较的类型。
|
|
|
+2|
|
|
|
+3| *T // 一个指针类型
|
|
|
+4| [5]T // 一个元素类型为T、元素个数为5的数组类型
|
|
|
+5| []T // 一个元素类型为T的切片类型
|
|
|
+6| map[Tkey]T // 一个键值类型为Tkey、元素类型为T的映射类型
|
|
|
+7|
|
|
|
+8| // 一个结构体类型
|
|
|
+9| struct {
|
|
|
+10| name string
|
|
|
+11| age int
|
|
|
+12| }
|
|
|
+13|
|
|
|
+14| // 一个函数类型
|
|
|
+15| func(int) (bool, string)
|
|
|
+16|
|
|
|
+17| // 一个接口类型
|
|
|
+18| interface {
|
|
|
+19| Method0(string) int
|
|
|
+20| Method1() (int, bool)
|
|
|
+21| }
|
|
|
+22|
|
|
|
+23| // 几个通道类型
|
|
|
+24| chan T
|
|
|
+25| chan<- T
|
|
|
+26| <-chan T
|
|
|
+```
|
|
|
+
|
|
|
+## Go 对面向对象编程的支持
|
|
|
+
|
|
|
+- 方法(22)
|
|
|
+- 实现(23)
|
|
|
+- 类型内嵌(24)
|
|
|
+
|
|
|
+## Go对泛型的支持
|
|
|
+
|
|
|
+- 泛型(26)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+# 指针
|
|
|
+
|
|
|
+## 指针类型和值
|
|
|
+
|
|
|
+在Go中,一个无名指针类型的字面形式为*T,其中T为一个任意类型。类型T称为 指针类型*T的基类型(base type)。 如果一个指针类型的基类型为T,则我们可 以称此指针类型为一个T指针类型。
|
|
|
+
|
|
|
+```go
|
|
|
+1| *int // 一个基类型为int的无名指针类型。
|
|
|
+2| **int // 一个多级无名指针类型,它的基类型为*int。
|
|
|
+3|
|
|
|
+4| type Ptr *int // Ptr是一个具名指针类型,它的基类型为int。
|
|
|
+5| type PP *Ptr // PP是一个具名多级指针类型,它的基类型为Ptr。
|
|
|
+
|
|
|
+```
|
|
|
+
|
|
|
+指针类型的零值的字面量用预声明的nil来表示。nil指针(常称为空指针)中不存储任何地址。
|
|
|
+
|
|
|
+如果一个指针类型的基类型为T,则此指针类型的值只能存储类型为T的值的地址。
|
|
|
+
|
|
|
+## 如何获取一个指针值
|
|
|
+
|
|
|
+1. 假设T是任一类型,调用new(T)返回一个类型为*T的指针值。存储在返回指针值所表示的地址处的值是T的零值。
|
|
|
+2. 可以用前置取地址操作符&来获取一个可寻址值的地址。 对于一 个类型为T的可寻址的值t,我们可以用&t来取得它的地址。&t的类型为 *T
|
|
|
+
|
|
|
+```go
|
|
|
+//有关解引用 值传递
|
|
|
+1| package main
|
|
|
+2|
|
|
|
+3| import "fmt"
|
|
|
+4|
|
|
|
+5| func main() {
|
|
|
+6| p0 := new(int) // p0指向一个int类型的零值
|
|
|
+7| fmt.Println(p0) // (打印出一个十六进制形式的地址)
|
|
|
+8| fmt.Println(*p0) // 0
|
|
|
+9|
|
|
|
+10| x := *p0 // x是p0所引用的值的一个复制。
|
|
|
+11| p1, p2 := &x, &x // p1和p2中都存储着x的地址。
|
|
|
+12| // x、*p1和*p2表示着同一个int值。
|
|
|
+13| fmt.Println(p1 == p2) // true
|
|
|
+14| fmt.Println(p0 == p1) // false
|
|
|
+15| p3 := &*p0 // <=> p3 := &(*p0)
|
|
|
+16| // <=> p3 := p0
|
|
|
+17| // p3和p0中存储的地址是一样的。
|
|
|
+18| fmt.Println(p0 == p3) // true
|
|
|
+19| *p0, *p1 = 123, 789
|
|
|
+20| fmt.Println(*p2, x, *p3) // 789 789 123
|
|
|
+21|
|
|
|
+22| fmt.Printf("%T, %T \n", *p0, x) // int, int
|
|
|
+23| fmt.Printf("%T, %T \n", p0, p1) // *int, *int
|
|
|
+24| }
|
|
|
+```
|
|
|
+
|
|
|
+## 为什么需要指针
|
|
|
+
|
|
|
+看懂就行啦
|
|
|
+其实就是创建修改了指针副本,但指针副本也是指向原指针的地址值,对副本的修改也会对原指针的地址值生效
|
|
|
+
|
|
|
+```go
|
|
|
+1| package main
|
|
|
+2|
|
|
|
+3| import "fmt"
|
|
|
+4|
|
|
|
+5| func double(x *int) {
|
|
|
+6| *x += *x
|
|
|
+7| x = nil // 此行仅为讲解目的
|
|
|
+8| }
|
|
|
+9|
|
|
|
+第15章:指针
|
|
|
+123
|
|
|
+10| func main() {
|
|
|
+11| var a = 3
|
|
|
+12| double(&a)
|
|
|
+13| fmt.Println(a) // 6
|
|
|
+14| p := &a
|
|
|
+15| double(p)
|
|
|
+16| fmt.Println(a, p == nil) // 12 false
|
|
|
+17| }
|
|
|
+
|
|
|
+```
|
|
|
+
|
|
|
+## Go中返回一个局部变量的地址是安全的
|
|
|
+
|
|
|
+Go支持垃圾回收,所以一个函数返回其内声明的局部变量的地址是 绝对安全的。比如:
|
|
|
+
|
|
|
+```go
|
|
|
+1| func newInt() *int {
|
|
|
+2| a := 3
|
|
|
+3| return &a
|
|
|
+4| }
|
|
|
+
|
|
|
+```
|
|
|
+
|
|
|
+## 指针比较赋值、要考虑类型
|
|
|
+
|
|
|
+Go指针值是支持(使用比较运算符==和!=)比较的。 但是,两个指针只有在下列任一条件被满足的时候才可以比较:
|
|
|
+
|
|
|
+1. 这两个指针的类型相同。
|
|
|
+2. 其中一个指针可以被隐式转换为另一个指针的类型。换句话说,这两个指针的 类型的底层类型必须一致并且至少其中一个指针类型为无名的(考虑结构体字 段的标签)。
|
|
|
+3. 其中一个并且只有一个指针用类型不确定的nil标识符表示。
|