一、Go基础知识16、指针详解

一、指针的定义与使用

Go语言中的指针与其他语言类似,用于存储变量的内存地址。指针变量可以指向任何数据类型,包括自定义类型。在Go中,声明指针使用*操作符,而通过&操作符可以获取变量的地址。

示例

package main

import "fmt"

func main() {
    // 定义一个整数变量
    var num int = 42

    // 声明一个指向整数的指针
    var ptr *int

    // 获取变量的地址,并将地址赋值给指针变量
    ptr = &num

    // 打印变量的值和地址
    fmt.Println("Value of num:", num)
    fmt.Println("Address of num:", &num)

    // 打印指针变量的值和指向的变量的值
    fmt.Println("Value of ptr:", ptr)
    fmt.Println("Value pointed by ptr:", *ptr)

    // 修改指向的变量的值
    *ptr = 99

    // 打印修改后的变量的值
    fmt.Println("Modified value of num:", num)
}

解释
在这个例子中,我们首先定义了一个整数变量 num,然后声明了一个指向整数的指针 ptr。通过 &num 获取了 num 变量的地址,并将地址赋值给指针变量 ptr。接着,我们打印了变量的值和地址,以及指针变量的值和指向的变量的值。最后,我们通过修改指针变量所指向的变量的值,来展示指针的修改效果。

结果:

Value of num: 42
Address of num: 0xc000016060
Value of ptr: 0xc000016060
Value pointed by ptr: 42
Modified value of num: 99

解释
这个例子中,ptr 指向了 num 的地址,通过 *ptr 可以访问该地址上的值。修改 *ptr 的值,实际上就是修改了 num 的值。

二、指针的初始化

在Go语言中,指针变量的初始化通常是通过new关键字或直接使用地址运算符&来完成的。

1、使用 new 关键字初始化指针

new 是一个内建函数,用于创建一个新的实例,并返回该实例的地址。可以将其用于初始化指针。

示例

package main

import "fmt"

func main() {
    // 使用 new 关键字初始化指针
    ptr := new(int)

    // 打印指针变量的值(指向的地址)
    fmt.Println("Value of ptr:", ptr)

    // 修改指向的变量的值
    *ptr = 42

    // 打印修改后的变量的值
    fmt.Println("Modified value:", *ptr)
}

结果:

Value of ptr: 0xc00007c020
Modified value: 42

解释
在这个例子中,new(int) 返回一个指向新分配的零值整数的指针。然后,我们通过*ptr访问指针所指向的整数,并将其修改为42。

2、直接使用地址运算符 & 初始化指针

示例

package main

import "fmt"

func main() {
    // 定义一个整数变量
    num := 10

    // 使用地址运算符 & 初始化指针
    ptr := &num

    // 打印指针变量的值(指向的地址)
    fmt.Println("Value of ptr:", ptr)

    // 打印指向的变量的值
    fmt.Println("Value pointed by ptr:", *ptr)

    // 修改指向的变量的值
    *ptr = 20

    // 打印修改后的变量的值
    fmt.Println("Modified value of num:", num)
}

结果:

Value of ptr: 0xc000016060
Value pointed by ptr: 10
Modified value of num: 20

解释
在这个例子中,我们首先定义了一个整数变量 num,然后使用 &num 获取 num 变量的地址,并将其赋值给指针变量 ptr。通过 *ptr 可以访问指针所指向的变量,并进行相应的修改。

三、通过swap交换指针的值

在Go语言中,可以通过指针来实现交换两个变量的值。这是因为通过指针,我们可以直接访问和修改内存中的数据。

示例

package main

import "fmt"

// swap 函数接受两个指向整数的指针,并交换它们所指向的值
func swap(a, b *int) {
    temp := *a
    *a = *b
    *b = temp
}

func main() {
    // 定义两个整数变量
    num1 := 10
    num2 := 20

    // 打印交换前的值
    fmt.Println("Before swap:")
    fmt.Println("num1:", num1)
    fmt.Println("num2:", num2)

    // 调用 swap 函数交换变量值,传递变量地址
    swap(&num1, &num2)

    // 打印交换后的值
    fmt.Println("\nAfter swap:")
    fmt.Println("num1:", num1)
    fmt.Println("num2:", num2)
}

结果:

Before swap:
num1: 10
num2: 20

After swap:
num1: 20
num2: 10

解释
在这个例子中,swap 函数接受两个指向整数的指针作为参数,然后通过指针操作,交换了这两个整数的值。在 main 函数中,我们定义了两个整数变量 num1num2,然后通过调用 swap 函数,传递这两个变量的地址,实现了它们的值的交换。最后,我们打印了交换前后的变量值,验证了交换的效果。

四、nil在go中的细节

在Go语言中,nil 是一个预定义的标识符,用于表示指针、切片、映射、通道、接口和函数等数据类型的零值或未初始化值。nil 通常用于表示某个指针或引用类型的零值,即它不指向任何有效的内存地址或数据。

以下是 nil 在不同数据类型中的用法和一些细节:

  1. 指针(Pointers)

    在Go中,指针的零值是 nil,表示指针未指向任何有效的内存地址。

    var ptr *int // 声明一个整数指针,其零值为 nil
    fmt.Println("Value of ptr:", ptr) // 输出: Value of ptr: <nil>
    
  2. 切片(Slices)

    未初始化的切片,其零值也是 nil

    var s []int // 未初始化的切片,零值为 nil
    fmt.Println("Value of slice:", s) // 输出: Value of slice: []
    
  3. 映射(Maps)

    未初始化的映射,其零值同样为 nil

    var m map[string]int // 未初始化的映射,零值为 nil
    fmt.Println("Value of map:", m) // 输出: Value of map: map[]
    
  4. 通道(Channels)

    未初始化的通道的零值也是 nil

    var ch chan int // 未初始化的通道,零值为 nil
    fmt.Println("Value of channel:", ch) // 输出: Value of channel: <nil>
    
  5. 接口(Interfaces)

    一个接口类型的零值是 nil,当且仅当其动态值和动态类型都为 nil

    var intf interface{} // 接口类型的零值为 nil
    fmt.Println("Value of interface:", intf) // 输出: Value of interface: <nil>
    

在使用 nil 时,需要小心处理,以避免出现空指针引用或其他相关的运行时错误。

示例

package main

import "fmt"

func main() {
    // 指针的零值是 nil
    var ptr *int
    fmt.Println("Value of ptr:", ptr) // 输出: Value of ptr: <nil>

    // 未初始化的切片零值是 nil
    var s []int
    fmt.Println("Value of slice:", s) // 输出: Value of slice: []

    // 未初始化的映射零值是 nil
    var m map[string]int
    fmt.Println("Value of map:", m) // 输出: Value of map: map[]

    // 未初始化的通道零值是 nil
    var ch chan int
    fmt.Println("Value of channel:", ch) // 输出: Value of channel: <nil>

    // 接口类型的零值是 nil
    var intf interface{}
    fmt.Println("Value of interface:", intf) // 输出: Value of interface: <nil>
}

五、指针的原理

在 Go 语言中,指针是一种特殊的变量类型,用来存储另一个变量的内存地址。指针变量可以指向任何数据类型(如整数、字符串、结构体、函数等),并允许直接访问其所指向的变量的值或修改它。

  1. 存储内存地址:指针变量存储另一个变量的内存地址。这个内存地址指向存储实际值的位置。

  2. 操作符 &:在 Go 中,通过使用操作符 & 可以获取一个变量的地址,生成一个指向该变量的指针。

  3. 操作符 *:指针的间接引用操作符 *,可以用于访问指针所指向的变量的值。通过 *ptr 访问指针 ptr 所指向的变量。

  4. 空指针(nil):指针变量的零值是 nil,表示它不指向任何有效的内存地址。

示例

package main

import "fmt"

func main() {
    var num int = 42 // 声明一个整数变量 num,并赋值为 42
    var ptr *int     // 声明一个整数指针变量 ptr

    ptr = &num       // 将 num 的地址赋值给指针 ptr

    fmt.Println("Value of num:", num)
    fmt.Println("Address of num:", &num)
    fmt.Println("Value of ptr:", ptr)
    fmt.Println("Value pointed by ptr:", *ptr) // 通过指针访问 num 的值

    *ptr = 100       // 通过指针修改 num 的值

    fmt.Println("\nValue of num after modification:", num) // num 的值已被修改
}

结果:

Value of num: 42
Address of num: 0xc0000140a8
Value of ptr: 0xc0000140a8
Value pointed by ptr: 42

Value of num after modification: 100

解释
在这个示例中,首先声明了一个整数变量 num 并赋值为 42。然后声明了一个整数指针变量 ptr。通过 &num 获取 num 的地址,并将其赋值给 ptr,使得 ptr 指向 num。通过 *ptr 可以访问 ptr 所指向的变量的值。最后,通过 *ptr = 100 修改了 num 的值,因为 ptr 指向了 num 的地址。因此,num 的值被修改为 100

  • 20
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风不归Alkaid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值