指针

指针的定义和使用

希望结构体传值时,我在函数中修改的值能反应到变量中

  • 定义
    `go
    package main

import (
“fmt”
)

type Person struct {
name string
}

func change(p *Person) {
p.name = “imo”
}

func main() {
p := Person{
name: “young”,
}
fmt.Println(p)
change(&p)
fmt.Println(p)

var pi *Person = &p
fmt.Println(pi, &p)
fmt.Printf("%p,%p", pi, &p) //打印出指针变量的地址
fmt.Println()
po := &Person{ //初始化
    name: "young2",
}

fmt.Println(po)

}

//输出
{young}
{imo}
&{imo} &{imo}
0xc00005c270,0xc00005c270
&{young2}


* 赋值
```go

type Person struct {
    name string
}

func main() {

    po := &Person{ //初始化
        name: "young2",
    }
    fmt.Println(po)
    (*po).name = "young3" //第一种赋值方式
    fmt.Println(po)
    po.name = "young4" //也可以当普通赋值方式 go内部优化
    fmt.Println(po)
}
//输出
C:\Users\Administrator\AppData\Local\Temp\GoLand\___10go_build_main_go.exe
&{young2}
&{young3}
&{young4}

指针与其他语言不同点,go是赋值不一样。还有个点是go限制了指针的运算,一般不参与运算。相当于阉割版,但是如果确实需要运算,可以用unsafe包。。因为指针运算过于灵活,新手开发较为容易出错。。所以需要用得调用unsafe包

指针的初始化

定义结构体不初始化会给默认值,但如果指针则不行,会抛出:
”无效的内存地址或无指针取消引用“的错误。

var p Person
    fmt.Println(p.name)
    结构体这样输出为空
var p *Person
    fmt.Println(p.name)
    指针的输出为这个错误
    panic: runtime error: invalid memory address or nil pointer dereference
  • 初始化方式
package main

import "fmt"

type Person struct {
    name string
}

func main() {

    p := &Person{} //第一种初始化

    var emptyP Person
    p2 := &emptyP                //第二种,结构体不用初始化(默认结构体已经初始化了),然后用指针指向它
    var p3 *Person = new(Person) //第三种 new 相当于new了个空的结构体(类似于第二种,简化,go的优化)
    fmt.Println(p.name, p2.name, p3.name)

    // map channel slice初始化推荐make方法
    //指针初始化推荐使用new函数,指针要初始化否则会出现nil pointer的的情况
    //map 需要初始化
}

通过swap交换指针的值

正常逻辑这样能实现交换值

func main() {

    a, b := 1, 2
    fmt.Println(a, b)
    a, b = b, a
    fmt.Println(a, b)
}
//输出
1 2
2 1

但是指针不能这么改,例如下面 ,由于指针值传递。下面仅仅是针对把a的地址变成b的地址,b的地址变成a的地址,但值没变(a 地址 0x01 值 1),(b 地址 0x02 值 2),变成 (a 地址 0x02 值 1),(b 地址 0x01 值 2)

func swap(a, b *int) {
    a, b = b, a
}
func main() {

    a, b := 1, 2
    fmt.Println(a, b)
    swap(&a, &b)
    fmt.Println(a, b)
}

//输出
1 2
1 2
  • 那么如何来改变呢?
func swap(a, b *int) {
    tmp := *a //取a地址的值,不能取变量,临时变量存储a地址的值

    *a = *b //将a地址的值改为b地址的值

    *b = tmp //将b地址的值改为a地址的值(由于a地址改了,所以得取tmp的)

}
func main() {

    a, b := 1, 2
    fmt.Println(a, b)
    swap(&a, &b)
    fmt.Println(a, b)
}

//输出
1 2
2 1


错误示例

func swap(a, b *int) {

    *a = *b //将a地址的值改为b地址的值

    *b = *a //将b地址的值改为a地址的值(由于a地址改了,所以得取tmp的)

}
func main() {

    a, b := 1, 2
    fmt.Println(a, b)
    swap(&a, &b)
    fmt.Println(a, b)
}
//输出 由于a地址的值变成b地址的值,所以b地址去取a地址的值时取得也是a地址的值。有点绕

1 2
2 2

nil在go中的细节

不同类型的数据 零值时不一样的
bool false
number 0
string “”
pointer nil
slice nil
map nil
channel、interface、function nil
struct 默认值不是nil、是具体字段的默认值。

判断时容易进入到非nil 例如

如图这个代码输出的是empty,而非nil
map类型这类最好用map去初始化

文档更新时间: 2023-07-09 02:37   作者:young