指针是内存地址的直接引用,存储变量地址并可解引用操作其值;切片是包含指针、长度和容量的结构体,通过指向底层数组实现数据管理,append超容时触发扩容并复制数据。

Golang中的指针和切片(Slice)在内存分配上,初看可能觉得有点绕,但一旦抓住核心,会发现它们各自有明确的逻辑。简单来说,指针就是内存地址的直接引用,指向一块具体的内存空间。而切片则更像一个智能的视图,它内部藏着一个指向底层数组的指针、当前长度和最大容量,它不是数据本身,而是数据的管理者。理解这两者,关键在于搞清楚Go语言里数据是如何在内存中被组织和访问的,这直接影响到程序的性能和潜在的内存问题。
要深入理解Go语言的内存模型,特别是指针和切片,我们得从它们在内存中的实际布局和行为说起。 指针,它本质上就是一个存储了另一个变量内存地址的变量。当你声明
var p *int
p
p = &someVar
p
someVar
*p
someVar
切片则复杂一些,但其设计哲学非常优雅。它不是一个简单的数组,而是一个包含三个字段的结构体:一个指向底层数组的指针(
Data
Len
Cap
make([]int, 0, 5)
Data
Len
Cap
append
Len
Cap
Len
Len
Cap
append
Data
append
说到底,Go语言里的指针,就是一种非常直接的内存地址引用。它不像某些高级语言那样,把内存细节封装得严严实实,但又不像C/C++那样,提供裸指针运算的自由(和危险)。在Go里,指针就是一个类型化的内存地址。比如
*int
int
var x int = 10
x
10
p := &x
p
10
x
p
0xc000014080
x
*p
*p
x
struct
package main
import "fmt"
func main() {
a := 10
fmt.Printf("变量a的值: %d, 地址: %p\n", a, &a) // %p 打印地址
var p *int // 声明一个指向int类型的指针
p = &a // 将a的地址赋值给p
fmt.Printf("指针p存储的地址: %p, p指向的值: %d\n", p, *p)
*p = 20 // 通过指针修改a的值
fmt.Printf("修改后变量a的值: %d\n", a)
// nil指针
var q *int
if q == nil {
fmt.Println("q 是一个 nil 指针")
}
// *q = 30 // 尝试解引用nil指针会导致运行时错误 (panic)
}可以看到,
nil
切片在Go语言里是个很独特的存在,它既不是纯粹的值类型,也不是传统意义上的引用类型。它的内部结构,用Go的
reflect
SliceHeader
type SliceHeader struct {
Data uintptr // 指向底层数组的指针
Len int // 切片的当前长度
Cap int // 切片的最大容量
}这个
SliceHeader
Data
立即学习“go语言免费学习笔记(深入)”;
内存分配上,
make
s := make([]int, 3, 5)
int
SliceHeader
Data
Len
Cap
s
append
s = append(s, elem)
s.Len < s.Cap
elem
s.Data[s.Len]
s.Len
s.Len == s.Cap
s.Data
s.Len
以上就是Golang指针与Slice类型内存分配解析的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号