987 lines
22 KiB
Go
987 lines
22 KiB
Go
/*
|
||
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. 主要用于系统编程和性能优化
|
||
*/ |