go语言学习笔记 — 基础 — 基本数据类型 — 指针:一文详解go指针

Posted Locutus

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言学习笔记 — 基础 — 基本数据类型 — 指针:一文详解go指针相关的知识,希望对你有一定的参考价值。

说到指针,许多人感到“谈指针色变”,对指针偏移、指针运算、指针转换非常恐惧。其实,指针是C族语言(C/C++)极高性能的根本,在操作大块数据和做内存地址偏移时,方便快捷。C族语言(C/C++)中指针被诟病的原因是 指针的运算内存释放

go中的指针分为两个重要方面:

  • 类型指针。类型指针拥有指针的高效访问:传递数据使用指针,而不是采用内存拷贝;使用类型指针修改(其指针地址)指向的普通变量值。类型指针不能运算和偏移
  • 切片。由指向起始元素的原始指针、元素数量和容量构成。切片比原始指针更安全高效,当切片越界时,go运行时会报panic,并打出堆栈,原始指针只能崩溃

1. 几个名词和过程

  • 普通变量

初始化普通变量,类型为T。

  • 取(内存)地址

使用&操作符,对普通变量取(内存)地址,得到普通变量的指针(变量)。

  • 指针(变量)

对普通变量取地址后(&(普通变量)),得到指针变量。在程序运行时,每个变量都会被分配内存,拥有内存地址。指针(变量)的值就是这个内存地址,也叫指针地址,这就是指针(变量)的本质。

注: 每个普通变量都有内存地址,指针的值就是这个内存地址。

  • 指针类型

使用&(普通变量),对普通变量取(内存)地址后,得到指针变量,其类型为*T,即T的指针类型。

  • 指针地址

指针变量的值是指针地址。指针地址带有"0x"的十六进制前缀。指针地址在64位平台上是64位内存地址,在32位平台上是32位地址。

  • 指针(变量)取值

使用*操作符,对指针变量取值,从指针变量中获取(指针地址指向的)原普通变量的值。

  • 操作符&*

取(内存)地址操作符&和取(指针变量)值操作符*是一对互补操作符:

1)使用&取出普通变量的(内存)地址得到指针变量

2)使用*对指针变量进行取值操作,获得指针指向的原普通变量值

3)*(*T)取出指针变量指向的原普通变量值,即*(*T)指向原来T类型的普通变量


2. 指针(变量):取指针地址(&)和指针类型(*T)

在程序运行时,每个变量都拥有一个(内存)地址,这个地址表示变量在内存中的位置。在go中,我们使用&对变量进行取地址操作。格式如下:

ptr := &ins    // 普通变量ins是T类型

ins表示普通变量,类型为T。使用&取内存地址,得到T的指针类型*T,赋给指针变量ptr(*T类型,T的指针类型)。*表示指针。

package main

import "fmt"

func main() {
    var cat int = 1
    
    var str string = "orange"
    
    // 打印指针变量的内存地址
    fmt.Printf("%p %p", &cat, &str)
}

// 0xc0000b8030 
// 0xc0000ae030

指针值带有"0x"的十六进制前缀。输出普通变量的指针地址每次都不同。


3. 从指针(变量)中获取(指针指向的)原普通变量的值

对指针使用*,即对指针取值。

package main

import (
	"fmt"
	"testing"
)

func main() {
	// var house = "mabuli point 10880, 90265"
	// house := "mabuli point 10880, 90265"
	var house string = "mabuli point 10880, 90265" // 初始化一个字符串类型的变量house

	ptr := &house // 对普通变量取内存地址,得到字符串指针类型,赋给指针变量ptr,是*string类型

	fmt.Printf("ptr type: %T\\n", ptr) // 获取指针变量的类型
	fmt.Printf("address: %p\\n", ptr)  // 获取指针变量的内存地址

	value := *ptr // 对指针变量取值

	fmt.Printf("value type: %T\\n", value)
	fmt.Printf("address: %s\\n", value)
}

/*
ptr type: *string
address: 0xc0000ae030
value type: string
address: mabuli point 10880, 90265
*/

4. 使用指针修改值(常用)

使用指针不仅可以获取普通变量对应的(内存)地址,还可以用来修改指针指向的普通变量值。

package ptr_test

import (
	"fmt"
	"testing"
)

// 使用指针进行数值交换:交换两个指针变量对应的(普通变量)值
func swap(a, b *int) {
	t := *a // 取a指针对应的普通变量值,赋给临时变量t

	*a = *b // 取b指针对应的普通变量值,赋给a指针对应的普通变量

	*b = t // 把a指针对应的普通变量值,赋给b指针指向的变量
	
	// b, a = a, b 交换指针变量的值,只是交换指针地址,并没交换指针地址指向的普通变量值

}

func TestPtrReviseCode(t *testing.T) {
	x, y := 1, 2

	swap(&x, &y) // 取普通变量的地址,得到指针变量,是指针类型*T,作为swap的入参

	fmt.Println(x, y) 
}

// 2 1

*指针变量 放在 := 的右侧,表示取指针变量指向的普通变量值,如 t := *a,取指针a指向的变量值,赋给变量t ;
*指针变量 放在 = 的左侧,表示把值设置给指向的变量,如 *b = t,把普通变量t的值,赋给指针b指向的变量。


5. 使用new( )函数创建指针(常用)

使用 new( ) 函数可以创建一个指针变量(初始化一个指针),得到一个对应类型的指针。创建过程会分配内存,指针指向的值为默认值。格式如下:

ins := new(类型)

创建一个指针变量str,它是一个字符串类型的指针。

package main

import "fmt"

func main() {
    str := new(string)
    *str = "ninja"

    fmt.Println(*str)
}

// ninja

以上是关于go语言学习笔记 — 基础 — 基本数据类型 — 指针:一文详解go指针的主要内容,如果未能解决你的问题,请参考以下文章

go语言学习笔记 — 基础 — 基本数据类型 — 字符串:字符

go语言学习笔记 — 基础 — 基本数据类型 — 原生数据类型:布尔型数字类型(整型与浮点型)字符串类型

go语言学习笔记 — 基础 — 基本数据类型 — 字符串(11):go中的字符串

go语言学习笔记 — 基础 — 基本数据类型 — 类型类别:值类型和引用类型

go语言学习笔记 — 基础 — 基本数据类型 — 字符串:遍历字符串

go语言学习笔记 — 基础 — 基本数据类型 — 字符串:修改字符串