Files
2025-08-24 01:15:18 +08:00

987 lines
22 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
05-pointers.go - Go 语言指针详解
学习目标:
1. 理解指针的概念和作用
2. 掌握指针的声明和使用
3. 学会指针的运算和操作
4. 了解指针与函数参数的关系
5. 掌握指针的实际应用场景
知识点:
- 指针的定义和特性
- 指针的声明和初始化
- 取地址操作符 &
- 解引用操作符 *
- 指针与函数参数
- 指针与结构体
- 指针的零值 nil
- 指针的安全使用
*/
package main
import (
"fmt"
)
func main() {
fmt.Println("=== Go 语言指针详解 ===\n")
// 演示指针的基本概念
demonstrateBasicPointers()
// 演示指针的操作
demonstratePointerOperations()
// 演示指针与函数
demonstratePointersWithFunctions()
// 演示指针与结构体
demonstratePointersWithStructs()
// 演示指针与数组/切片
demonstratePointersWithArraysSlices()
// 演示指针的高级用法
demonstrateAdvancedPointerUsage()
// 演示指针的实际应用
demonstratePracticalApplications()
}
// demonstrateBasicPointers 演示指针的基本概念
func demonstrateBasicPointers() {
fmt.Println("1. 指针的基本概念:")
// 指针的基本特性
fmt.Printf(" 指针的基本特性:\n")
fmt.Printf(" - 存储变量的内存地址\n")
fmt.Printf(" - 通过地址间接访问变量\n")
fmt.Printf(" - 零值是 nil\n")
fmt.Printf(" - 类型安全,不支持指针运算\n")
fmt.Printf(" - 自动垃圾回收管理\n")
// 基本指针示例
fmt.Printf(" 基本指针示例:\n")
// 声明变量
var x int = 42
fmt.Printf(" 变量 x: %d\n", x)
fmt.Printf(" x 的地址: %p\n", &x)
// 声明指针
var p *int
fmt.Printf(" 指针 p 的零值: %v\n", p)
fmt.Printf(" p == nil: %t\n", p == nil)
// 指针赋值
p = &x
fmt.Printf(" p = &x 后:\n")
fmt.Printf(" p 的值(地址): %p\n", p)
fmt.Printf(" p 指向的值: %d\n", *p)
fmt.Printf(" p 的地址: %p\n", &p)
// 通过指针修改值
*p = 100
fmt.Printf(" *p = 100 后:\n")
fmt.Printf(" x 的值: %d\n", x)
fmt.Printf(" *p 的值: %d\n", *p)
// 指针的类型
fmt.Printf(" 指针的类型:\n")
var intPtr *int
var floatPtr *float64
var stringPtr *string
fmt.Printf(" *int 指针: %T\n", intPtr)
fmt.Printf(" *float64 指针: %T\n", floatPtr)
fmt.Printf(" *string 指针: %T\n", stringPtr)
fmt.Println()
}
// demonstratePointerOperations 演示指针的操作
func demonstratePointerOperations() {
fmt.Println("2. 指针的操作:")
// 取地址操作符 &
fmt.Printf(" 取地址操作符 &:\n")
a := 10
b := 20
c := 30
fmt.Printf(" 变量地址:\n")
fmt.Printf(" &a: %p\n", &a)
fmt.Printf(" &b: %p\n", &b)
fmt.Printf(" &c: %p\n", &c)
// 解引用操作符 *
fmt.Printf(" 解引用操作符 *:\n")
ptr := &a
fmt.Printf(" ptr 指向 a: %p\n", ptr)
fmt.Printf(" *ptr: %d\n", *ptr)
// 修改指针指向
ptr = &b
fmt.Printf(" ptr 指向 b: %p\n", ptr)
fmt.Printf(" *ptr: %d\n", *ptr)
// 指针赋值
fmt.Printf(" 指针赋值:\n")
var p1, p2 *int
p1 = &a
p2 = p1 // 指针赋值,两个指针指向同一地址
fmt.Printf(" p1: %p, *p1: %d\n", p1, *p1)
fmt.Printf(" p2: %p, *p2: %d\n", p2, *p2)
fmt.Printf(" p1 == p2: %t\n", p1 == p2)
// 通过不同指针修改同一变量
*p1 = 99
fmt.Printf(" *p1 = 99 后:\n")
fmt.Printf(" a: %d\n", a)
fmt.Printf(" *p2: %d\n", *p2)
// nil 指针检查
fmt.Printf(" nil 指针检查:\n")
var nilPtr *int
fmt.Printf(" nilPtr: %v\n", nilPtr)
fmt.Printf(" nilPtr == nil: %t\n", nilPtr == nil)
// 安全的指针使用
if nilPtr != nil {
fmt.Printf(" *nilPtr: %d\n", *nilPtr)
} else {
fmt.Printf(" nilPtr 是 nil不能解引用\n")
}
// 指针比较
fmt.Printf(" 指针比较:\n")
x, y := 1, 2
px, py := &x, &y
px2 := &x
fmt.Printf(" px == py: %t (指向不同变量)\n", px == py)
fmt.Printf(" px == px2: %t (指向同一变量)\n", px == px2)
fmt.Printf(" px == nil: %t\n", px == nil)
fmt.Println()
}
// demonstratePointersWithFunctions 演示指针与函数
func demonstratePointersWithFunctions() {
fmt.Println("3. 指针与函数:")
// 值传递 vs 指针传递
fmt.Printf(" 值传递 vs 指针传递:\n")
x := 10
fmt.Printf(" 原始值: %d\n", x)
// 值传递
modifyByValue(x)
fmt.Printf(" 值传递后: %d (未改变)\n", x)
// 指针传递
modifyByPointer(&x)
fmt.Printf(" 指针传递后: %d (已改变)\n", x)
// 函数返回指针
fmt.Printf(" 函数返回指针:\n")
ptr := createInt(42)
fmt.Printf(" 返回的指针: %p\n", ptr)
fmt.Printf(" 指针指向的值: %d\n", *ptr)
// 多个返回值包含指针
value, valuePtr := createIntPair(100)
fmt.Printf(" 返回值: %d\n", value)
fmt.Printf(" 返回指针: %p, 值: %d\n", valuePtr, *valuePtr)
// 指针作为函数参数的优势
fmt.Printf(" 指针作为函数参数的优势:\n")
// 交换变量
a, b := 5, 10
fmt.Printf(" 交换前: a=%d, b=%d\n", a, b)
swap(&a, &b)
fmt.Printf(" 交换后: a=%d, b=%d\n", a, b)
// 避免大结构体拷贝
fmt.Printf(" 避免大结构体拷贝:\n")
person := Person{Name: "Alice", Age: 25, Email: "alice@example.com"}
fmt.Printf(" 修改前: %+v\n", person)
// 使用指针避免结构体拷贝
updatePersonByPointer(&person, 26)
fmt.Printf(" 指针修改后: %+v\n", person)
fmt.Println()
}
// demonstratePointersWithStructs 演示指针与结构体
func demonstratePointersWithStructs() {
fmt.Println("4. 指针与结构体:")
// 结构体指针的创建
fmt.Printf(" 结构体指针的创建:\n")
// 方式1: 先创建结构体,再取地址
person1 := Person{Name: "Alice", Age: 25, Email: "alice@example.com"}
personPtr1 := &person1
fmt.Printf(" 方式1: %+v\n", *personPtr1)
// 方式2: 直接创建结构体指针
personPtr2 := &Person{Name: "Bob", Age: 30, Email: "bob@example.com"}
fmt.Printf(" 方式2: %+v\n", *personPtr2)
// 方式3: 使用 new 函数
personPtr3 := new(Person)
personPtr3.Name = "Charlie"
personPtr3.Age = 35
personPtr3.Email = "charlie@example.com"
fmt.Printf(" 方式3: %+v\n", *personPtr3)
// 结构体指针的字段访问
fmt.Printf(" 结构体指针的字段访问:\n")
// 方式1: 显式解引用
fmt.Printf(" (*personPtr1).Name: %s\n", (*personPtr1).Name)
// 方式2: 自动解引用(推荐)
fmt.Printf(" personPtr1.Name: %s\n", personPtr1.Name)
// 修改结构体字段
fmt.Printf(" 修改结构体字段:\n")
fmt.Printf(" 修改前: %s\n", personPtr1.Name)
personPtr1.Name = "Alice Smith"
fmt.Printf(" 修改后: %s\n", personPtr1.Name)
fmt.Printf(" 原结构体: %s\n", person1.Name) // 也被修改了
// 结构体指针切片
fmt.Printf(" 结构体指针切片:\n")
people := []*Person{
{Name: "David", Age: 28, Email: "david@example.com"},
{Name: "Eve", Age: 32, Email: "eve@example.com"},
{Name: "Frank", Age: 29, Email: "frank@example.com"},
}
fmt.Printf(" 人员列表:\n")
for i, person := range people {
fmt.Printf(" %d: %s (%d岁)\n", i+1, person.Name, person.Age)
}
// 修改切片中的结构体
people[0].Age = 29
fmt.Printf(" 修改后第一个人的年龄: %d\n", people[0].Age)
// 结构体指针映射
fmt.Printf(" 结构体指针映射:\n")
userMap := map[string]*Person{
"alice": {Name: "Alice", Age: 25, Email: "alice@example.com"},
"bob": {Name: "Bob", Age: 30, Email: "bob@example.com"},
}
if user, exists := userMap["alice"]; exists {
fmt.Printf(" 找到用户: %+v\n", *user)
user.Age = 26 // 修改映射中的结构体
fmt.Printf(" 修改后: %+v\n", *user)
}
fmt.Println()
}
// demonstratePointersWithArraysSlices 演示指针与数组/切片
func demonstratePointersWithArraysSlices() {
fmt.Println("5. 指针与数组/切片:")
// 数组指针
fmt.Printf(" 数组指针:\n")
arr := [5]int{1, 2, 3, 4, 5}
arrPtr := &arr
fmt.Printf(" 数组: %v\n", arr)
fmt.Printf(" 数组指针: %p\n", arrPtr)
fmt.Printf(" 通过指针访问: %v\n", *arrPtr)
// 修改数组元素
arrPtr[2] = 99 // 等同于 (*arrPtr)[2] = 99
fmt.Printf(" 修改后数组: %v\n", arr)
// 元素指针
fmt.Printf(" 元素指针:\n")
slice := []int{10, 20, 30, 40, 50}
fmt.Printf(" 切片: %v\n", slice)
// 获取元素指针
elemPtr := &slice[2]
fmt.Printf(" slice[2] 的地址: %p\n", elemPtr)
fmt.Printf(" slice[2] 的值: %d\n", *elemPtr)
// 通过元素指针修改
*elemPtr = 300
fmt.Printf(" 修改后切片: %v\n", slice)
// 指针切片
fmt.Printf(" 指针切片:\n")
var intPtrs []*int
for i := range slice {
intPtrs = append(intPtrs, &slice[i])
}
fmt.Printf(" 指针切片长度: %d\n", len(intPtrs))
fmt.Printf(" 第一个指针指向的值: %d\n", *intPtrs[0])
// 通过指针切片修改原切片
*intPtrs[1] = 200
fmt.Printf(" 修改后原切片: %v\n", slice)
// 数组指针 vs 指针数组
fmt.Printf(" 数组指针 vs 指针数组:\n")
// 数组指针:指向数组的指针
var arrayPtr *[3]int = &[3]int{1, 2, 3}
fmt.Printf(" 数组指针类型: %T\n", arrayPtr)
fmt.Printf(" 数组指针值: %v\n", *arrayPtr)
// 指针数组:元素是指针的数组
x, y, z := 1, 2, 3
var ptrArray [3]*int = [3]*int{&x, &y, &z}
fmt.Printf(" 指针数组类型: %T\n", ptrArray)
fmt.Printf(" 指针数组值: [%d, %d, %d]\n", *ptrArray[0], *ptrArray[1], *ptrArray[2])
fmt.Println()
}// demons
trateAdvancedPointerUsage 演示指针的高级用法
func demonstrateAdvancedPointerUsage() {
fmt.Println("6. 指针的高级用法:")
// 双重指针
fmt.Printf(" 双重指针:\n")
x := 42
ptr := &x
ptrPtr := &ptr
fmt.Printf(" x: %d\n", x)
fmt.Printf(" ptr: %p, *ptr: %d\n", ptr, *ptr)
fmt.Printf(" ptrPtr: %p, *ptrPtr: %p, **ptrPtr: %d\n", ptrPtr, *ptrPtr, **ptrPtr)
// 通过双重指针修改
**ptrPtr = 100
fmt.Printf(" **ptrPtr = 100 后, x: %d\n", x)
// 指针与接口
fmt.Printf(" 指针与接口:\n")
var shape Shape
// 值类型实现接口
circle := Circle{Radius: 5}
shape = circle
fmt.Printf(" 圆形面积: %.2f\n", shape.Area())
// 指针类型实现接口
rect := &Rectangle{Width: 4, Height: 3}
shape = rect
fmt.Printf(" 矩形面积: %.2f\n", shape.Area())
// 指针与方法集
fmt.Printf(" 指针与方法集:\n")
counter := Counter{Value: 0}
fmt.Printf(" 初始计数器: %+v\n", counter)
// 值类型调用指针接收者方法(自动取地址)
counter.Increment()
fmt.Printf(" 调用 Increment() 后: %+v\n", counter)
// 指针类型调用值接收者方法(自动解引用)
counterPtr := &Counter{Value: 10}
value := counterPtr.GetValue()
fmt.Printf(" 指针调用值方法: %d\n", value)
// unsafe 包的使用(谨慎使用)
fmt.Printf(" unsafe 包的使用:\n")
var num int64 = 0x1234567890ABCDEF
fmt.Printf(" 原始值: 0x%X\n", num)
// 获取指针
numPtr := unsafe.Pointer(&num)
// 将 int64 指针转换为 int32 指针低32位
lowPtr := (*int32)(numPtr)
fmt.Printf(" 低32位: 0x%X\n", *lowPtr)
// 获取高32位
highPtr := (*int32)(unsafe.Pointer(uintptr(numPtr) + 4))
fmt.Printf(" 高32位: 0x%X\n", *highPtr)
// 指针大小
fmt.Printf(" 指针大小:\n")
fmt.Printf(" 指针大小: %d 字节\n", unsafe.Sizeof(ptr))
fmt.Printf(" uintptr 大小: %d 字节\n", unsafe.Sizeof(uintptr(0)))
fmt.Println()
}
// demonstratePracticalApplications 演示指针的实际应用
func demonstratePracticalApplications() {
fmt.Println("7. 指针的实际应用:")
// 应用1: 链表实现
fmt.Printf(" 应用1 - 链表实现:\n")
list := &LinkedList{}
// 添加节点
list.Add(1)
list.Add(2)
list.Add(3)
fmt.Printf(" 链表内容: ")
list.Print()
// 查找节点
if list.Contains(2) {
fmt.Printf(" 链表包含值 2\n")
}
// 删除节点
list.Remove(2)
fmt.Printf(" 删除 2 后: ")
list.Print()
// 应用2: 树结构
fmt.Printf(" 应用2 - 二叉树:\n")
tree := &BinaryTree{}
// 插入节点
tree.Insert(5)
tree.Insert(3)
tree.Insert(7)
tree.Insert(1)
tree.Insert(9)
fmt.Printf(" 中序遍历: ")
tree.InorderTraversal()
fmt.Printf("\n")
// 查找节点
if tree.Search(7) {
fmt.Printf(" 树中包含值 7\n")
}
// 应用3: 缓存系统
fmt.Printf(" 应用3 - LRU 缓存:\n")
cache := NewLRUCache(3)
// 添加缓存项
cache.Put("a", 1)
cache.Put("b", 2)
cache.Put("c", 3)
fmt.Printf(" 缓存状态: ")
cache.Print()
// 访问缓存项
if value, found := cache.Get("b"); found {
fmt.Printf(" 获取 'b': %d\n", value)
}
// 添加新项(会淘汰最久未使用的)
cache.Put("d", 4)
fmt.Printf(" 添加 'd' 后: ")
cache.Print()
// 应用4: 对象池
fmt.Printf(" 应用4 - 对象池:\n")
pool := NewObjectPool()
// 获取对象
obj1 := pool.Get()
obj2 := pool.Get()
fmt.Printf(" 获取对象1: %p\n", obj1)
fmt.Printf(" 获取对象2: %p\n", obj2)
// 使用对象
obj1.Data = "Hello"
obj2.Data = "World"
fmt.Printf(" 对象1数据: %s\n", obj1.Data)
fmt.Printf(" 对象2数据: %s\n", obj2.Data)
// 归还对象
pool.Put(obj1)
pool.Put(obj2)
// 再次获取(可能复用之前的对象)
obj3 := pool.Get()
fmt.Printf(" 再次获取对象: %p (数据: %s)\n", obj3, obj3.Data)
// 应用5: 回调函数
fmt.Printf(" 应用5 - 回调函数:\n")
processor := &DataProcessor{}
// 设置回调函数
processor.SetCallback(func(data string) {
fmt.Printf(" 处理数据: %s\n", data)
})
// 处理数据
processor.Process("Hello, World!")
// 应用6: 观察者模式
fmt.Printf(" 应用6 - 观察者模式:\n")
subject := &Subject{}
// 添加观察者
observer1 := &Observer{Name: "Observer1"}
observer2 := &Observer{Name: "Observer2"}
subject.AddObserver(observer1)
subject.AddObserver(observer2)
// 通知观察者
subject.NotifyObservers("重要消息")
fmt.Println()
}
// ========== 类型定义 ==========
// 基本结构体
type Person struct {
Name string
Age int
Email string
}
// 几何图形接口
type Shape interface {
Area() float64
}
// 圆形
type Circle struct {
Radius float64
}
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
// 矩形
type Rectangle struct {
Width float64
Height float64
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
// 计数器
type Counter struct {
Value int
}
func (c *Counter) Increment() {
c.Value++
}
func (c Counter) GetValue() int {
return c.Value
}
// 链表节点
type ListNode struct {
Value int
Next *ListNode
}
// 链表
type LinkedList struct {
Head *ListNode
}
func (l *LinkedList) Add(value int) {
newNode := &ListNode{Value: value}
if l.Head == nil {
l.Head = newNode
} else {
current := l.Head
for current.Next != nil {
current = current.Next
}
current.Next = newNode
}
}
func (l *LinkedList) Contains(value int) bool {
current := l.Head
for current != nil {
if current.Value == value {
return true
}
current = current.Next
}
return false
}
func (l *LinkedList) Remove(value int) {
if l.Head == nil {
return
}
if l.Head.Value == value {
l.Head = l.Head.Next
return
}
current := l.Head
for current.Next != nil {
if current.Next.Value == value {
current.Next = current.Next.Next
return
}
current = current.Next
}
}
func (l *LinkedList) Print() {
current := l.Head
for current != nil {
fmt.Printf("%d ", current.Value)
current = current.Next
}
fmt.Printf("\n")
}
// 二叉树节点
type TreeNode struct {
Value int
Left *TreeNode
Right *TreeNode
}
// 二叉树
type BinaryTree struct {
Root *TreeNode
}
func (t *BinaryTree) Insert(value int) {
t.Root = t.insertNode(t.Root, value)
}
func (t *BinaryTree) insertNode(node *TreeNode, value int) *TreeNode {
if node == nil {
return &TreeNode{Value: value}
}
if value < node.Value {
node.Left = t.insertNode(node.Left, value)
} else {
node.Right = t.insertNode(node.Right, value)
}
return node
}
func (t *BinaryTree) Search(value int) bool {
return t.searchNode(t.Root, value)
}
func (t *BinaryTree) searchNode(node *TreeNode, value int) bool {
if node == nil {
return false
}
if value == node.Value {
return true
} else if value < node.Value {
return t.searchNode(node.Left, value)
} else {
return t.searchNode(node.Right, value)
}
}
func (t *BinaryTree) InorderTraversal() {
t.inorderNode(t.Root)
}
func (t *BinaryTree) inorderNode(node *TreeNode) {
if node != nil {
t.inorderNode(node.Left)
fmt.Printf("%d ", node.Value)
t.inorderNode(node.Right)
}
}
// LRU 缓存节点
type CacheNode struct {
Key string
Value int
Prev *CacheNode
Next *CacheNode
}
// LRU 缓存
type LRUCache struct {
Capacity int
Cache map[string]*CacheNode
Head *CacheNode
Tail *CacheNode
}
func NewLRUCache(capacity int) *LRUCache {
head := &CacheNode{}
tail := &CacheNode{}
head.Next = tail
tail.Prev = head
return &LRUCache{
Capacity: capacity,
Cache: make(map[string]*CacheNode),
Head: head,
Tail: tail,
}
}
func (c *LRUCache) Get(key string) (int, bool) {
if node, exists := c.Cache[key]; exists {
c.moveToHead(node)
return node.Value, true
}
return 0, false
}
func (c *LRUCache) Put(key string, value int) {
if node, exists := c.Cache[key]; exists {
node.Value = value
c.moveToHead(node)
} else {
newNode := &CacheNode{Key: key, Value: value}
c.Cache[key] = newNode
c.addToHead(newNode)
if len(c.Cache) > c.Capacity {
tail := c.removeTail()
delete(c.Cache, tail.Key)
}
}
}
func (c *LRUCache) addToHead(node *CacheNode) {
node.Prev = c.Head
node.Next = c.Head.Next
c.Head.Next.Prev = node
c.Head.Next = node
}
func (c *LRUCache) removeNode(node *CacheNode) {
node.Prev.Next = node.Next
node.Next.Prev = node.Prev
}
func (c *LRUCache) moveToHead(node *CacheNode) {
c.removeNode(node)
c.addToHead(node)
}
func (c *LRUCache) removeTail() *CacheNode {
lastNode := c.Tail.Prev
c.removeNode(lastNode)
return lastNode
}
func (c *LRUCache) Print() {
current := c.Head.Next
for current != c.Tail {
fmt.Printf("(%s:%d) ", current.Key, current.Value)
current = current.Next
}
fmt.Printf("\n")
}
// 对象池
type PoolObject struct {
Data string
}
type ObjectPool struct {
pool []*PoolObject
}
func NewObjectPool() *ObjectPool {
return &ObjectPool{
pool: make([]*PoolObject, 0),
}
}
func (p *ObjectPool) Get() *PoolObject {
if len(p.pool) > 0 {
obj := p.pool[len(p.pool)-1]
p.pool = p.pool[:len(p.pool)-1]
return obj
}
return &PoolObject{}
}
func (p *ObjectPool) Put(obj *PoolObject) {
obj.Data = "" // 重置对象
p.pool = append(p.pool, obj)
}
// 数据处理器
type DataProcessor struct {
callback func(string)
}
func (d *DataProcessor) SetCallback(callback func(string)) {
d.callback = callback
}
func (d *DataProcessor) Process(data string) {
if d.callback != nil {
d.callback(data)
}
}
// 观察者模式
type Observer struct {
Name string
}
func (o *Observer) Update(message string) {
fmt.Printf(" %s 收到消息: %s\n", o.Name, message)
}
type Subject struct {
observers []*Observer
}
func (s *Subject) AddObserver(observer *Observer) {
s.observers = append(s.observers, observer)
}
func (s *Subject) NotifyObservers(message string) {
for _, observer := range s.observers {
observer.Update(message)
}
}
// ========== 辅助函数 ==========
// 值传递函数
func modifyByValue(x int) {
x = 999
fmt.Printf(" 函数内部: %d\n", x)
}
// 指针传递函数
func modifyByPointer(x *int) {
*x = 888
fmt.Printf(" 函数内部: %d\n", *x)
}
// 返回指针的函数
func createInt(value int) *int {
x := value // 局部变量
return &x // 返回局部变量的地址Go 会自动分配到堆上)
}
// 返回值和指针
func createIntPair(value int) (int, *int) {
x := value
return x, &x
}
// 交换函数
func swap(a, b *int) {
*a, *b = *b, *a
}
// 更新结构体
func updatePersonByPointer(p *Person, newAge int) {
p.Age = newAge
}
/*
运行这个程序:
go run 05-pointers.go
学习要点:
1. 指针存储变量的内存地址,通过地址间接访问变量
2. 使用 & 获取地址,使用 * 解引用指针
3. 指针的零值是 nil使用前要检查
4. 指针传参可以避免大对象拷贝,允许函数修改原变量
5. Go 的指针是类型安全的,不支持指针运算
指针的特性:
1. 类型安全:不同类型的指针不能相互赋值
2. 自动管理:垃圾回收器自动管理内存
3. 无指针运算:不支持 C 风格的指针运算
4. 自动解引用:结构体指针可以直接访问字段
5. 方法调用:自动在值和指针间转换
指针的用途:
1. 避免大对象拷贝
2. 允许函数修改参数
3. 实现数据结构(链表、树等)
4. 共享数据
5. 可选值表示
指针与函数:
1. 值传递:传递变量的拷贝
2. 指针传递:传递变量的地址
3. 返回指针:可以返回局部变量的地址
4. 方法接收者:值接收者 vs 指针接收者
最佳实践:
1. 使用前检查指针是否为 nil
2. 大结构体使用指针传递
3. 需要修改参数时使用指针
4. 合理使用指针避免内存泄漏
5. 优先使用值类型,必要时使用指针
常见应用场景:
1. 数据结构实现
2. 对象池和缓存
3. 回调函数
4. 观察者模式
5. 链式数据结构
6. 可选参数
注意事项:
1. nil 指针解引用会 panic
2. 指针比较比较的是地址
3. 指针可能导致内存泄漏
4. 避免返回栈变量的指针Go 会自动处理)
5. 理解值接收者和指针接收者的区别
unsafe 包:
1. 提供底层内存操作
2. 绕过类型安全检查
3. 谨慎使用,可能破坏内存安全
4. 主要用于系统编程和性能优化
*/