• GoLong的学习之路(六)语法之指针


    书接上回,上回书中写道,数组已经和java中数组的区别。在go中数组的是数值类型,故需要指针指向数组的地址,从而进行修改。这次诉说,指针

    指针

    区别于C/C++中的指针,Go语言中的指针不能进行偏移和运算,是安全指针。(难度直接向下)

    要搞明白Go语言中的指针需要先知道3个概念:指针地址、指针类型和指针取值。

    指针地址

    在内存中,一个数据需要存储,但是不能光存储,不去处理。要处理就必须在众多的数据中锁定我们所需的数据,这个就像,是在茫茫人海中一眼就看到你(只在灯火阑珊处)。所以此时就需要一个能够找到你的位置,也就是--------地址(在内存中,地址通常以32位,16进制表示)

    我在程序中把赋值给变量A,把内存地址赋值给变量B。这时候变量B就是一个指针变量。

    Go语言中的指针不能进行偏移和运算,因此Go语言中的指针操作非常简单,我们只需要记住两个符号:&(取地址)(获取引用)和 *(根据地址取值)(解引用)。

    每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。

    • Go语言中使用 & 字符放在变量前面对变量进行“取地址”操作。

    • Go语言中的值类型(int、float、bool、string、array、struct)都有对应的指针类型,如:*int、*int64、*string等。

    func main() {
    	a := 10
    	b := &a
    	fmt.Printf("a:%d ptr:%p\n", a, &a) // a:10 ptr:0xc00001a078
    	fmt.Printf("b:%p type:%T\n", b, b) // b:0xc00001a078 type:*int
    	fmt.Println(&b)                    // 0xc00000e018
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    a :代表被取地址的变量,类型为 int
    b:用于接收地址的变量,ptr的类型就为 *int,称做 int 的指针类型。*代表指针。

    在这里插入图片描述

    变量、指针地址、指针变量、取地址、取值的相互关系和特性:

    • 对变量进行进行取地址( & )操作,可以获取这个变量的指针变量
    • 指针变量的值是指针地址
    • 对指针变量进行取值( * )操作,可以获取指针变量指向的原变量的值
    func main() {
    	//指针取值
    	a := 10
    	b := &a // 取变量a的地址,将指针保存到b中
    	fmt.Printf("type of b:%T\n", b)
    	c := *b // 指针取值(根据指针去内存取值)
    	fmt.Printf("type of c:%T\n", c)
    	fmt.Printf("value of c:%v\n", c)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值。

    import "fmt"
    
    func modifyArray(x int) {
    	x = 100
    }
    
    func modifyArray2(x *int) {
    	*x = 100
    }
    
    func main() {
    	//指针取值
    	a := 10
    	modifyArray(a)
    	fmt.Println(a)//10
    	
    	modifyArray2(&a)
    	fmt.Println(a)//100
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    new和make

    为什么会有这两个?其实我说实话我也挺懵逼的,看来到哪里都逃不过被new的命运。

    在Go语言中对于引用类型的变量,我们在使用的时候不仅要声明它,还要为它分配内存空间,否则我们的值就没办法存储。

    如错误例子:

    func main() {
    	var a *int
    	*a = 100
    	fmt.Println(*a)
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    在这里我只做了声明但是没有给他分配内存空间,所以在底层迟迟找不到,然后就报超时。

    对于值类型的声明不需要分配内存空间,是因为它们在声明的时候已经默认分配好了内存空间。

    所以为了让我们声明的引用类型有内存空间,所以此时我们就需要,引入两个关键字对这种变量分配内存空间。

    Go语言中new和make是内建的两个函数,主要用来分配内存。(如果是C语言就需要有释放内存的步骤,但是Go有自动回收的机制)

    new

    new是一个内置的函数:它的函数签名如下:

    func new(Type) *Type
    
    • 1

    在这里插入图片描述

    • Type表示类型,new函数只接受一个参数,这个参数是一个类型
    • *Type表示类型指针,new函数返回一个指向改类型内存地址的指针。

    如何正确使用?

    func main() {
    	// 声明指针类型
    	var a *int
    	// 为指针类型分配内空间
    	a = new(int)
    	// 进行赋值
    	*a = 10
    	fmt.Println(*a)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    var a *int只是声明了一个指针变量a但是没有初始化,指针作为引用类型需要初始化后才会拥有内存空间,才可以给它赋值。

    总结一下:

    1. 声明指针类型
    2. 为指针类型分配空间
    3. 进行赋值

    make

    make也是用于内存分配,区别于new,它只是slice,map以及channel的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型本身就是引用类型。所以没有必要去返回一个指针类型了。

    make函数是无可替代的,我们在使用slice、map以及channel的时候,都需要使用make进行初始化,然后才可以对它们进行操作。(这三个函数在后续会有讲解)

    make的函数签名:

    func make(t Type, size ...IntegerType) Type
    
    • 1
    func main() {
    	var b map[string]int
    	b = make(map[string]int, 10)
    	b["你好"] = 100
    	fmt.Println(b)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    用的还是之前的三板斧

    new与make的区别

    1. 二者都是用来分配内存空间的
    2. make只试用slice、map、以及channel的初始话,返回的还是这三个引用类型本身;
    3. new使用于类型的内存分配,并且内存对应的值为类型默认值,返回的是指向类型的指针
  • 相关阅读:
    学习视觉SLAM需要会些什么?
    Nginx 解析漏洞
    window下redis安装
    C#学习相关系列之匿名方法和Lambda表达式
    Python之socket简玩
    10个python爬虫入门实例
    1532_AURIX_TriCore内核架构_中断
    C++学习之强制类型转换
    阿里云的ACA认证到底是个啥?有用吗?
    HarmonyOS应用开发者认证题目满分指南
  • 原文地址:https://blog.csdn.net/Cheer_RIO/article/details/133995434