Go语言指针变量

1. 指针变量

区别于C/C++中的指针,Go语言中的指针不能进行偏移和运算,是安全指针。

Go语言中的指针3个概念:指针地址、指针类型和指针取值。

1.1. Go语言中的指针

Go语言中的函数传参都是值拷贝,当我们想要修改某个变量的时候,我们可以创建一个指向该变量地址的指针变量。传递数据使用指针,而无须拷贝数据。类型指针不能进行偏移和运算。Go语言中的指针操作非常简单,只需要记住两个符号:&(取地址)和*(根据地址取值)。

1.2. 指针地址和指针类型

每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go语言中使用&字符放在变量前面对变量进行“取地址”操作。 Go语言中的值类型(int、float、bool、string、array、struct)都有对应的指针类型,如:*int、*int64、*string等。

取变量指针的语法如下:

    ptr := &v    // v的类型为T

其中:

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

举个例子:

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
}

我们来看一下b := &a的图示:

指针

1.3. 指针取值

在对普通变量使用&操作符取地址后会获得这个变量的指针,然后可以对指针使用*操作,也就是指针取值,代码如下。

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)
}

输出如下:

    type of b:*int
    type of c:int
    value of c:10

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

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

    1.对变量进行取地址(&)操作,可以获得这个变量的指针变量。
    2.指针变量的值是指针地址。
    3.对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值。

指针传值示例:

func modify1(x int) {
    x = 100
}

func modify2(x *int) {
    *x = 100
}

func main() {
    a := 10
    modify1(a)
    fmt.Println(a) // 10
    modify2(&a)
    fmt.Println(a) // 100
}

1.4. 空指针

  • 当一个指针被定义后没有分配到任何变量时,它的值为 nil
  • 空指针的判断
package main

import "fmt"

func main() {
    var p *string
    fmt.Println(p)
    fmt.Printf("p的值是%s/n", p)
    if p != nil {
        fmt.Println("非空")
    } else {
        fmt.Println("空值")
    }
}

1.5. new和make

我们先来看一个例子:

func main() {
    var a *int
    *a = 100
    fmt.Println(*a)

    var b map[string]int
    b["测试"] = 100
    fmt.Println(b)
}

执行上面的代码会引发panic,为什么呢? 在Go语言中对于引用类型的变量,我们在使用的时候不仅要声明它,还要为它分配内存空间,否则我们的值就没办法存储。而对于值类型的声明不需要分配内存空间,是因为它们在声明的时候已经默认分配好了内存空间。要分配内存,就引出来今天的new和make。 Go语言中new和make是内建的两个函数,主要用来分配内存

1.6. new

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

    func new(Type) *Type

其中,

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

new函数不太常用,使用new函数得到的是一个类型的指针,并且该指针对应的值为该类型的零值。举个例子:

func main() {
    a := new(int)
    b := new(bool)
    fmt.Printf("%T\n", a) // *int
    fmt.Printf("%T\n", b) // *bool
    fmt.Println(*a)       // 0
    fmt.Println(*b)       // false
}

本节开始的示例代码中var a *int只是声明了一个指针变量a但是没有初始化,指针作为引用类型需要初始化后才会拥有内存空间,才可以给它赋值。应该按照如下方式使用内置的new函数对a进行初始化之后就可以正常对其赋值了:

func main() {
    var a *int
    a = new(int)
    *a = 10
    fmt.Println(*a)
}

1.7. make

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

func make(t Type, size ...IntegerType) Type

make函数是无可替代的,我们在使用slice、map以及channel的时候,都需要使用make进行初始化,然后才可以对它们进行操作。这个我们在上一章中都有说明,关于channel我们会在后续的章节详细说明。

本节开始的示例中var b map[string]int只是声明变量b是一个map类型的变量,需要像下面的示例代码一样使用make函数进行初始化操作之后,才能对其进行键值对赋值:

func main() {
    var b map[string]int
    b = make(map[string]int, 10)
    b["测试"] = 100
    fmt.Println(b)
}

1.8. new与make的区别

    1.二者都是用来做内存分配的。
    2.make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身;
    3.而new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。

1.9. 指针小练习

  • 程序定义一个int变量num的地址并打印
  • 将num的地址赋给指针ptr,并通过ptr去修改num的值
package main

import "fmt"

func main() {
    var a int
    fmt.Println(&a)
    var p *int
    p = &a
    *p = 20
    fmt.Println(a)
}

2.相关使用

2.1 修改数组项的值

错误示范:

for i, _ := range list {
        //go中所有传递都属于只拷贝
        item:=list[i]
		item.Password = ""
		if !item.IsLocked() {
			item.BlockTime = xtime.Zero()
		}
	}

正确示范1: 

for i, _ := range list {
		list[i].Password = ""
		if !list[i].IsLocked() {
			list[i].BlockTime = xtime.Zero()
		}
	}

正确示范2:

for i, _ := range list {
        item:=&list[i]
		item.Password = ""
		if !item.IsLocked() {
			item.BlockTime = xtime.Zero()
		}
	}

从上面的代码可以看出go中的值传递都是采用的只拷贝。

三种方式写法的区别:

第一种写法修改的值是拷贝后的值,对list中的项不会有任何影响

第二种写法直接修改list[i],这种完全没问题

第三种则是把list[i]对应的地址传递给item,那么修改item是完全没问题的,因为它修改的是地址

参考文章:

https://www.fansimao.com/940382.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/348950.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Top Down - Fantasy Forest (HDRP)

适用于任何自上而下游戏的近180个风格化资产的强大集合!无论是RTS、MOBA、RPG还是Hacknslash,此包都可以让您制作完整而详细的自上而下关卡。 特点: 共计177个预制件和4个粒子效果 6 个可平铺的地形纹理 7 棵树模型 24个灌木丛、草地和植物 14个蘑菇 20个资源节点(金、铁、…

04-了解所有权

上一篇: 03-常用编程概念 所有权是 Rust 最独特的特性,对语言的其他部分有着深刻的影响。它使 Rust 可以在不需要垃圾回收器的情况下保证内存安全,因此了解所有权的工作原理非常重要。在本章中,我们将讨论所有权以及几个相关特性&…

Ngnix负载均衡

配置Ngnix环境 1.安装 创建Nginx的目录: mkdir /soft && mkdir /soft/nginx/ cd /home/centos/nginx下载Nginx安装包通过wget命令在线获取安装包: wget https://nginx.org/download/nginx-1.21.6.tar.gz解压Nginx压缩包: tar -x…

RT-Thread: 串口操作、增加串口、串口函数

说明:本文记录RT-Thread添加串口的步骤和串口的使用。 1.新增串口 官方链接:https://www.rt-thread.org/document/site/rtthread-studio/drivers/uart/v4.0.2/rtthread-studio-uart-v4.0.2/ 新增串口只需要在 board.h 文件中定义相关串口的宏定…

宋仕强论道之华强北的缺货潮(十六)

始于2019年缺货潮让华强北又生产一大批亿万富翁,缺货的原因主要是:首先,疫情封控导致大量白领在家远程办公,需要购买电脑、打印机等办公设备,同时孩子们也要在家上网课,进一步增加对电子智能终端产品的需求…

Java实现天沐瑜伽馆管理系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 瑜伽课程模块2.3 课程预约模块2.4 系统公告模块2.5 课程评价模块2.6 瑜伽器械模块 三、系统设计3.1 实体类设计3.1.1 瑜伽课程3.1.2 瑜伽课程预约3.1.3 系统公告3.1.4 瑜伽课程评价 3.2 数据库设计3.2.…

口腔炎症和灼口综合征的区别有哪些?

随着社会发展的进步,当代人面临的压力越来越大,口腔疾病也随之而来。那么懂得如何分辨口腔疾病就至关重要。在我们绝大多数人眼里,口腔疾病都会统称为“上火”,但是不同的口腔疾病有不同症状和现象,如果没有早发现&…

C语言练习题110例(十)

91.杨辉三角 题目描述: KK知道什么叫杨辉三角之后对杨辉三角产生了浓厚的兴趣,他想知道杨辉三角的前n行,请编程帮他 解答。杨辉三角,本质上是二项式(ab)的n次方展开后各项的系数排成的三角形。其性质包括:每行的端点数为1&…

数据类型(下)

数据类型(下) 1.集合(set)1.1 定义1.2 独有功能1.3 公共功能1.4 转换1.5 其他1.5.1 集合的存储原理1.5.2 元素必须可哈希1.5.3 查找速度特别快1.5.4 对比和嵌套 练习题 强插:None类型2.字典(dict)2.1 定义2…

go sync.Pool 设计与实现

本文基于 Go 1.19 Pool 是一组可以安全在多个 goroutine 间共享的临时对象的集合。 存储在 Pool 中的任何项目都可能在任何时候被移除,因此 Pool 不适合保存那些有状态的对象,如数据库连接、TCP 连接等。 Pool 的目的是缓存已分配但未使用的项以供以后使…

java数据结构与算法刷题-----LeetCode565. 数组嵌套

java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846 解题思路 将数组抽象成链表,效果如下图所示 题目的要求&#x…

【VTKExamples::PolyData】第十九期 ImplicitDataSetClipping

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 前言 本文分享VTK样例ImplicitDataSetClipping,并解析接口vtkIdFilter & vtkBox & vtkClipPolyData,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就…

利用sqlmap探测get类型注入

环境准备:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客 基础:GET基于报错的sql注入利用-脱库-CSDN博客 sqlmap 工具是kali自带的 例子我都用sql靶场的第一关做演示 1、探测数据库名 sqlmap -u "http://192.168.0.103/sqlilab…

VUE--VUEX

一、什么是Vuex Vuex就是一个vue的状态(数据)管理工具,是vue项目实现大范围数据共享的技术方案。能够方便、高效的实现组件之间的数据共享。 Vuex的好处: (1)数据的存储一步到位,不需要层层传递…

HCIA学习作业二

要求:基于192.168.1.0/24进行合理划分,要求全网通 [AR3]display ip interface brief [AR3]display ip routing-table [AR1]display ip interface brief [AR1]display ip routing-table [AR2]display ip interface brief [AR2]display ip routing-tab…

arco design table遇到的一些问题

问题1:不知情就成了树形table table中不知道为啥就多了个树形加号在前面,查找问题后发现,是后端返回的数据中有children,框架中默认对这个参数做了树形结构。 解决办法: 当时没找到取消或者修改字段的属性或方法&…

使用vscode查bug

具体操作 修改CMakeList.txt # set(CMAKE_BUILD_TYPE "Release")//注释Release模式 set(CMAKE_BUILD_TYPE "Debug")//设置为Debug模式 # set(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wall -g")//注释*这行代码是用来设置 CMake 构建系统中 Release 模式…

nginx限制ip访问

先看一下被禁止的效果 如何配置 禁止访问的话直接在location模块增加类似如下配置 deny all; 完整示例 location / {deny all;root html;index index.html index.htm;} 默认是allow all就是允许所有ip访问,如果只配置指定ip可以访问是无效的,还是所有的ip可以访问 无效示例…

APPium简介及安装

1 APPium简介 1. 什么是APPium? APPium是一个开源测试自动化框架,适用于原生、混合或移动Web应用程序的自动化测试工具。 APPium使用WebDriver协议驱动iOS、Android等应用程序。 2. APPium的特点 支持多平台(Android、iOS等) …

【RA6M3 HMI Board线下培训笔记】 RT Thread实现物联网应用 ETH+MQTT+LVGL+RTOS 实现温湿度监测

【RA6M3 HMI Board线下培训笔记】 RT Thread实现物联网应用 ETHMQTTLVGLRTOS 实现温湿度监测 1. 序言 随着物联网技术的飞速发展,越来越多的生活场景变得越来越智能,网联化、智能化越来越成为主旋律。 值此之际,RT-Thread 和 瑞萨电子共同…