Go 语言学习笔记-指针、切片与结构体

指针

指针就是地址。指针变量就是存储地址的变量

指针使用

&p : 引用
*p : 解引用、间接引用

栈帧

用来给函数运行提供内存空间。取内存于 stack 上。

当函数调用时,产生栈帧。函数调用结束,释放栈帧。

  • 栈帧存储:
    • 局部变量
    • 形参 (形参与局部变量存储地位等同)
    • 内存字段描述值

指针使用注意

空指针:未被初始化的指针。

var p *int
fmt.Println(*p)  --> err

格式化输出

%q:以 Go 语言格式显示字符串。默认带有 "" 符
%v:显示对应数据详细信息

变量存储

func swap(x, y *int)  {
    *x, *y = *y, *x
}

等号左边的变量:代表变量所指向的内存空间。(写)
等号右边的变量:代表变量内存空间存储的数据值。(读)

指针的函数传参(传引用)

传地址(引用):将形参的地址值作为函数参数传递。
传值(数据):将实参的值拷贝一份给形参
传引用:在 A 栈帧内部,修改 B 栈帧中的变量值

切片

为什么用切片

  1. 数组的容量固定,不能自动拓展。
  2. 值传递。数组作为函数参数时,将整个数组值拷贝一份给形参。

在 Go 语言中,几乎可以在所有的场景中,使用切片替换数组使用。

切片的本质:

不是一个数组的指针,是一种数据结构体,用来操作数组内部元素。

// runtime/slice.go
type slice struct {
  *p
  len
  cap
}

切片的使用

  • 数组和切片定义区别:

    • 创建数组时 []指定数组长度
    • 创建切片时,[] 为空,或者 ...
  • 切片名称[low:high:max]

    • low:启示下标位置
    • high:结束下表位置
    • 长度 len:high - low
    • 容量 cap:max-low
  • 截取数组,初始化切片时,没有指定切片容量时,切片容量跟随原数组(切片)

    • s[:high:max]:从 0 开始,到 high 结束。(不包含 high)
    • s[low:]:从 low 开始,到末尾
    • s[:high]:从 0 开始,到 high 结束。容量跟随原先容量。【常用】
  • 切片创建:

    • 自动推导类型创建切片。slice := []int{1, 2, 3}
    • slice := make([]int, 长度, 容量)
    • slice := make([]int, 长度) 创建切片时,没有指定容量,容量==长度
  • 切片做函数参数 --- 传引用(传地址)

  • append:再切片末尾追加元素

    • append(切片对象, 待追加元素)
    • 向切片增加元素时,切片的容量会自动增加。1024 以下时,一两倍方式增加
  • copy 复制切片

    • copy(目标位置切片s1,源切片s2)
    • 拷贝过程中,直接对应位置拷贝
      • 不同类型的切片无法复制
      • 如果s1的长度大于s2的长度,将s2中对应位置上的值替换s1中对应位置的值。如果s1的长度小于s2的长度,多余的将不做替换

map

字典、映射,key-value, key:唯一、无需。不能是引用类型数据。

  • 创建方式:

    • var m map[int]string ---不能存储数据
    • m := map[int]string{} ---能存储数据
    • m := make(map[int]string) ---默认 len = 0
    • m := make(map[int]string, 10)
  • 初始化:

    • var m map[int]string = map[int]string{1: "aaa", 2: "bbb"} 保证 key 彼此不重复
    • m := map[int]string{1: "aaa", 2: "bbb"}
  • 赋值:

    • 赋值过程中,如果新 map 元素的 key 与原 map 元素 key 相同 ---> 覆盖(替换)
    • 赋值过程中,如果新 map 元素的 key 与原 map 元素 key 不同 ---> 添加
  • map 的使用

    • 遍历 map
    for key, value := range map {
    
    }
    
    • 判断 map 中 key 是否存在
      • map[下标] 运算:返回两个值,第一个表示 value 的值,如果 value 不存在,则为 nil。第二个表示 key 是否存在的 bool 类型,存在为 true,不存在为 false
      val, has := map[1]
      
  • 删除 map

    • delete()函数:
      • 参数1:待删除元素的 map
      • 参数2:key 值
    • delete(map, key)
      • 删除一个不存在的 key,不会报错
    • map 做函数参数和返回值,传引用

结构体

结构体是一种数据类型。类型定义,地位等价于 int、byte、bool、string…,通常放在全局位置。

type Person struct {
  name string
  sex  byte
  age  int
}

普通变量定义和初始化

  • 顺序初始化:依次将结构体内部所有成员初始化
    var man Person = Person{"andy", 'm', 20}
    
  • 指定成员初始化:未初始化的成员变量,取该数据类型对应的默认值
    man := Person{name: "andy", age: 20}
    

普通变量的赋值和使用

  • 使用 . 索引成员变量
    var man Person
    man.name = "nike"
    man.sex = 'm'
    man.age = 99
    

结构体变量的比较

  • 比较:只能使用 ==!=,不能使用 > < >= <= …
  • 相同结构体类型(成员变量的类型、个数、顺序一致),变量之间可以直接赋值

结构体地址

结构体变量的地址 == 结构体首个元素的地址

结构体传参

  • 将结构体变量的值拷贝一份传递。 ---几乎不用。内存消耗大,效率低。

  • unSafe.Sizeof(变量名) ---查看此种类型的变量所占用的内存空间大小

指针变量定义和初始化

  • 顺序初始化:依次将结构体内部所有成员初始化

    var man *Person = &Person{"andy", 'm', 20}
    
  • new(Person)

p := new(Person)
p.name = "name"
p.age = 10

指针索引成员变量

  • 使用 . 索引成员变量
    var man Person
    man.name = "nike"
    man.sex = 'm'
    man.age = 99
    

结构体地址

结构体指针变量的值 == 结构体首个元素的地址

结构体指针传参

  • 将结构体变啊零地址值传递(传引用)。---使用频率非常高

  • unSafe.Sizeof(指针):不管何种类型的指针,在 64位操作系统下,大小一致,均为 8 byte

结构体指针作函数返回值

  • 可以返回局部变量的值

  • 不能返回局部变量的地址 --- 局部变量保存在栈帧上,函数调用结束后,栈帧释放,局部变量的地址,不再受系统保护,随时可能分配给其他程序。

字符串处理函数

  • 字符串按指定分隔符拆分:Split:

    ret := strings.Split(str, "-")
    
  • 字符串按空格拆分:Fields

    ret = strings.Fields(str)
    
  • 判断字符串结束标记: HasSuffix

    flg := strings.HasSuffix("test.txt", ".aaa")
    
  • 判断字符串起始标识:HasPrefix

    flg := strings.HasPrefix("test.txt", "te.")
    

你可能感兴趣的:(Go 语言学习笔记-指针、切片与结构体)