跳到主要内容

2-引用类型

指针 Pointer

package main

import "fmt"

// 接受一个数字,并将其置为 0
func zeroValue(value int) {
value = 0
}

// 接受指针类型,修改指针对应的值为 0
func zeroPointer(ptr *int) {
*ptr = 0
}

func main() {
i := 1
iPtr := &i // iPtr 为指针,存储变量 i 的地址
fmt.Println("i:", i)
fmt.Println("iPtr:", iPtr)

// 尝试改变 i 的值,修改失败(仅仅是把变量 i 的值传入了函数,相当于没操作 i 变量)
zeroValue(i)
fmt.Println("zeroValue(i),i=", i)
// 尝试用 i 的指针来修改 i 的值,修改成功
zeroPointer(iPtr)
fmt.Println("zeroPointer(iPtr),i=", i)
// 指针也有自己的地址
fmt.Println("&i=", iPtr)
fmt.Println("&iPtr=", &iPtr)
}

// 指针是个特殊的变量,用来存储地址

// 指针也是变量,也有自己的地址

// 指针是可以直接操作的,但不推荐,需要用到很多 unsafe 的方法

// i := 1
// j := 2
// 二者地址刚好差 8 位,因为都占用了 64 个字节
// Go 的变量内存分配是反向的 从大到小

// js中没有指针类型,只有引用的概念,无法区分变量的值和地址,只能操作变量的值

切片 Slice

package main

import (
"fmt"
"reflect"
)

func main() {
// 区别数组与切片
arr := [...]int{1, 2, 3}
slice := []int{1, 2, 3}
slice2 := make([]int, 3)
typeArr := reflect.TypeOf(arr).Kind()
typeSlice := reflect.TypeOf(slice).Kind()
fmt.Println(typeArr, typeSlice, slice2)
// 遍历1
for i := 0; i < len(slice); i++ {
fmt.Println(slice[i])
}
// 遍历2
for i, v := range slice {
fmt.Println(i, v)
}
// 追加元素 注意需要重新赋值
slice = append(slice, 4, 5, 6)
fmt.Println(slice)
// slice 的本质是一个结构体,是对数组类型的二次封装内部有三个属性
// 分别是定长 array 的指针,数组长度 len 和数组容量 cap
// 扩容的过程
var s []bool
for i := 0; i < 66; i++ {
s = append(s, true)
fmt.Printf("定长数组地址:%p, 容量:%v\n", s, cap(s))
}
// 每当容量不足时,slice 会抛弃原来定长数组的内容空间,翻倍申请一块新的内容空间,并将原来的数据复制过去,同时 array 指针指向这里
// 在 256 以内是直接翻两倍,大于 256 后就变为 1.25 倍到 2 倍,防止浪费内存空间

// 切取
arr2 := [...]int{1, 2, 3, 4, 5, 6}
slice11 := arr2[0:3] // 左闭右开 [1,2,3]
slice12 := arr2[:3] // 初始的 0 可以省略
slice13 := arr2[:] // 结尾的 len 可以省略
fmt.Println(slice11, slice12, slice13)

}

哈希表 Map

package main

import "fmt"

func main() {
// 声明
// map[key的类型]value的类型
myMap := map[string]int{"apple": 100, "banana": 200}
fmt.Println(myMap["apple"])
myMap2 := make(map[string]int)
myMap2["water"] = 10
fmt.Println(myMap2)
var myMap3 map[string]int // 不能向这里面设置值???
fmt.Println(myMap3)
// 操作map
// 新增或修改
myMap2["book"] = 10
// 读取
book := myMap2["book"]
fmt.Println("book", book)
// 获取 length
fmt.Println("len", len(myMap2))
// 删除 key
delete(myMap2, "book")
// 检测 key
_, hasKey := myMap2["book"]
fmt.Println("hasKey", hasKey)
// 遍历 map
for key, value := range myMap2 {
fmt.Println(key, value)
}
// 每次都会在随机位置开始遍历
}

通道 Chan

package main

import (
"fmt"
"time"
)

func main() {
ch := make(chan string) // 创建 chan,只接受 string 消息

go func() { // 启动go程
fmt.Println("gofunc", 1)
time.Sleep(1 * time.Second) //休息1s
fmt.Println("gofunc", 2)
time.Sleep(1 * time.Second) //休息1s
ch <- "ping" // 往 chan 发送一个 string
}()

message := <-ch // 等待 string 传出
fmt.Println("main", message)
}

接口 interface

package main

import "fmt"

// 只要存在 toString 方法,就满足 Printable 接口
type Printable interface {
toString() string
}
type User struct {
name string
// 结构体中只能定义属性,不能定义方法
}

// 结构体方法的定义(注意不是函数,而是方法)
// func (实例 结构体) 方法名() 返回值类型 {}
func (u User) toString() string {
return u.name
}

// 要求参数满足 Printable 的要求,才能执行 print 函数
func print(p Printable) {
fmt.Println(p.toString())
}

func main() {
u := User{"gsq"}
print(u) // gsq
}