Go语言指针切片(存储指针的切片)
切片是一种比较特殊的数据结构,这种数据结构更便于使用和管理数据集合。切片是围绕动态数组的概念构建的,可以按需自动增长和缩小,总的来说,切片可理解为动态数组,并根据切片里的元素自动调整切片长度。
Go 语言的切片指针是以切片表示的,切片的每个元素只能存放内存地址,切片指针的语法定义如下:
切片指针的定义与切片定义是相同的,只要在数据类型前面使用符号“*”即可变为切片指针。由于切片有多种不同的定义方式,因此切片指针也会有多种定义方式,这里只列举了常用的定义方式。
切片指针可以将多个变量的内存地址存放在切片中,这样方便管理多个变量,当需要修改某个变量的时候,由于变量的内存地址是不会改变的,直接修改变量或者从切片指针修改变量即可,修改后的数据都会同步到变量和切片指针中,示例如下:
如果不掌握切片指针的基本原理,在实际开发中程序很容易埋下难以寻找的 bug,示例如下:
如果要修改上述问题,只能在第一次 for 循环中重新定义变量 a,每次循环为变量 a 重新赋予新的内存地址,代码如下:
Go 语言的切片指针是以切片表示的,切片的每个元素只能存放内存地址,切片指针的语法定义如下:
// 定义方式一
var name []*type
// 定义方式二
name := []*type{}
语法说明如下:
- name代表指针变量名,可自行命名,但必须遵从标识符命名规则。
- type是指针变量的数据类型,如数字、字符串等 Go 语言内置的数据类型。
切片指针的定义与切片定义是相同的,只要在数据类型前面使用符号“*”即可变为切片指针。由于切片有多种不同的定义方式,因此切片指针也会有多种定义方式,这里只列举了常用的定义方式。
切片指针可以将多个变量的内存地址存放在切片中,这样方便管理多个变量,当需要修改某个变量的时候,由于变量的内存地址是不会改变的,直接修改变量或者从切片指针修改变量即可,修改后的数据都会同步到变量和切片指针中,示例如下:
package main
import "fmt"
func main() {
// 定义一个空的字符串类型的切片指针
var pslice []*string
fmt.Printf("切片指针的元素:%v,内存地址:%v\n", pslice, &pslice)
// 定义变量a、b、c并赋值
var a, b string
a, b = "a", "b"
fmt.Printf("变量a、b的内存地址:%v、%v\n", &a, &b)
// 使用内置函数方法append()将变量a、b、c的内存地址添加到切片指针
pslice = append(pslice, &a)
pslice = append(pslice, &b)
fmt.Printf("切片指针的元素:%v\n", pslice)
// 输出切片指针的元素所对应的数值
// 使用取值操作符“*”从内存地址取值
for _, k := range pslice{
fmt.Printf("切片指针的元素所对应值:%v\n", *k)
}
// 从切片指针修改变量a的值,输出变量a
*pslice[0] = "hello"
fmt.Printf("修改后的变量值为:%v\n", a)
// 修改变量b的值,输出切片指针的变量b的值
b = "Golang"
fmt.Printf("修改后的变量值为:%v\n", *pslice[1])
}
运行上述代码,运行结果为:
切片指针的元素:[],内存地址:0xc00000e028
变量a、b的内存地址:0xc000010200、0xc000010210
切片指针的元素:[0xc000010200 0xc000010210]
切片指针的元素所对应值:a
切片指针的元素所对应值:b
修改后的变量值为:hello
修改后的变量值为:Golang
- 切片指针定义后,如果没有设置初始值,默认为空,由于切片是动态数组,其数据长度能自动调整,Go 语言不会分配内存地址,因此无法通过取地址操作符“&”获取切片指针的内存地址。
- 若将变量 a、b 写入切片指针,只能将变量 a、b 的内存地址写入切片指针,切片指针只能存放内存地址的数据格式。
- 使用 for-range 循环输出切片指针,只能输出存放在切片指针的内存地址,如果要通过内存地址获取对应数值,需要使用取值操作符“*”。
- 修改变量的值不会改变变量的内存地址,所以修改变量 a 或变量 b 的值,再从切片指针中获取变量 a 或变量 b 的值,输出结果都是变量 a 或变量 b 修改后的数值。同理,如果从切片指针中修改变量 a 或变量 b 的值,输出的变量 a 或变量 b 的值都是修改后的数值。
如果不掌握切片指针的基本原理,在实际开发中程序很容易埋下难以寻找的 bug,示例如下:
package main
import (
"fmt"
"strconv"
)
func main() {
// 定义一个空的字符串类型的切片指针
var pslice []*string
// 定义字符串类型的变量a
var a string
// 循环5次,当前循环次数赋值给变量a,再写入切片指针
for i := 0; i < 5; i++ {
a = strconv.Itoa(i)
pslice = append(pslice, &a)
}
// 输出切片指针的元素的数值
for _, k := range pslice {
fmt.Printf("切片指针的元素:%v,元素的值:%v\n", k, *k)
}
}
分析上述代码,它定义了变量 a 和切片指针 pslice,再执行了两次 for 循环。第一次 for 循环是将每次循环次数赋值给变量 a,然后将变量 a 的内存地址写入切片指针 pslice;第二次 for 循环是输出切片指针 pslice 的元素和元素值,运行结果为:
切片指针的元素:0xc000010200,元素的值:4
切片指针的元素:0xc000010200,元素的值:4
切片指针的元素:0xc000010200,元素的值:4
切片指针的元素:0xc000010200,元素的值:4
切片指针的元素:0xc000010200,元素的值:4
如果要修改上述问题,只能在第一次 for 循环中重新定义变量 a,每次循环为变量 a 重新赋予新的内存地址,代码如下:
package main
import (
"fmt"
"strconv"
)
func main() {
// 定义一个空的字符串类型的切片指针
var pslice []*string
// 循环5次,当前循环次数赋值给变量a,再写入切片指针
for i := 0; i < 5; i++ {
// 定义字符串类型的变量a
var a string
a = strconv.Itoa(i)
pslice = append(pslice, &a)
}
// 输出切片指针的元素的数值
for _, k := range pslice {
fmt.Printf("切片指针的元素:%v,元素的值:%v\n", k, *k)
}
}
运行上述代码,运行结果为:
切片指针的元素:0xc000010200,元素的值:0
切片指针的元素:0xc000010210,元素的值:1
切片指针的元素:0xc000010220,元素的值:2
切片指针的元素:0xc000010230,元素的值:3
切片指针的元素:0xc000010240,元素的值:4
ICP备案:
公安联网备案: