Go 指针
指针
在编程中,一个内存地址用来定位一段内存。
通常地,一个内存地址用一个操作系统原生字(native word)来存储。 一个原生字在32位操作系统上占4个字节,在64位操作系统上占8个字节。 所以,32位操作系统上的理论最大支持内存容量为4GB(1GB == 230字节),64位操作系统上的理论最大支持内存容量为264Byte,即16EB(EB:艾字节,1EB == 1024PB, 1PB == 1024TB, 1TB == 1024GB)。
内存地址的字面形式常用整数的十六进制字面量来表示,比如0x1234CDEF。
在Go中,一个无名指针类型的字面形式为*T,其中T为一个任意类型。类型T称为指针类型*T的基类型(base type)。 如果一个指针类型的基类型为T,则我们可以称此指针类型为一个T指针类型。
虽然我们可以声明具名指针类型,但是一般不推荐这么做,因为无名指针类型的可读性更高。
如果一个指针类型的底层类型是*T,则它的基类型为T。
如果两个无名指针类型的基类型为同一类型,则这两个无名指针类型亦为同一类型。
*int // 一个基类型为int的无名指针类型。
**int // 一个多级无名指针类型,它的基类型为*int。type Ptr *int // Ptr是一个具名指针类型,它的基类型为int。
type PP *Ptr // PP是一个具名多级指针类型,它的基类型为Ptr。如何获取一个指针值?
有两种方式来得到一个指针值:
我们可以用内置函数new来为任何类型的值开辟一块内存并将此内存块的起始地址做为此值的地址返回。 假设T是任一类型,则函数调用new(T)返回一个类型为*T的指针值。 存储在返回指针值所表示的地址处的值(可被看作是一个匿名变量)为T的零值。
我们也可以使用前置取地址操作符&来获取一个可寻址的值的地址。 对于一个类型为T的可寻址的值t,我们可以用&t来取得它的地址。&t的类型为*T。
一般说来,一个可寻址的值是指被放置在内存中某固定位置处的一个值(但放置在某固定位置处的一个值并非一定是可寻址的)。 目前,我们只需知道所有变量都是可以寻址的;但是所有常量、函数返回值和强制转换结果都是不可寻址的。 当一个变量被声明的时候,Go运行时将为此变量开辟一段内存。此内存的起始地址即为此变量的地址。
对于基类型为T的指针类型的一个指针值p,我们可以用*p来表示地址p处的值。 此值的类型为T。*p称为指针p的解引用。解引用是取地址的逆过程。
解引用一个nil指针将产生一个panic。
package mainimport "fmt"func main() {p0 := new(int) // p0指向一个int类型的零值fmt.Println(p0) // (打印出一个十六进制形式的地址)fmt.Println(*p0) // 0x := *p0 // x是p0所引用的值的一个复制。p1, p2 := &x, &x // p1和p2中都存储着x的地址。// x、*p1和*p2表示着同一个int值。fmt.Println(p1 == p2) // truefmt.Println(p0 == p1) // falsep3 := &*p0 // <=> p3 := &(*p0)// <=> p3 := p0// p3和p0中存储的地址是一样的。fmt.Println(p0 == p3) // true*p0, *p1 = 123, 789fmt.Println(*p2, x, *p3) // 789 789 123fmt.Printf("%T, %T \n", *p0, x) // int, intfmt.Printf("%T, %T \n", p0, p1) // *int, *int
}在Go中,所有的赋值(包括函数调用传参)过程都是一个值复制过程。 所以在上面的double函数体内修改的是变量a的一个副本,而没有修改变量a本身。
当然我们可以让double函数返回输入参数的两倍数,但是此方法并非适用于所有场合。
package mainimport "fmt"func double(x *int) {*x += *xx = nil // 此行仅为讲解目的
}func main() {var a = 3double(&a)fmt.Println(a) // 6p := &adouble(p)fmt.Println(a, p == nil) // 12 false
}通过将double函数的输入参数的类型改为*int,传入的实参&a和它在此函数体内的一个副本x都引用着变量a。 所以对*x的修改等价于对*p(也就是变量a)的修改。 换句话说,新版本的double函数内的操作可以反映到此函数外了。
当然,在此函数体内对传入的指针实参的修改x = nil依旧不能反映到函数外,因为此修改发生在此指针的一个副本上。 所以在double函数调用之后,局部变量p的值并没有被修改为nil。
在Go中返回一个局部变量的地址是安全的
Go是支持垃圾回收的,所以一个函数返回其内声明的局部变量的地址是绝对安全的。
func newInt() *int {a := 3return &a
}Go指针的一些限制
施加限制,Go指针保留了C指针的好处,同时也避免了C指针的危险性。
在Go中,指针是不能参与算术运算的。比如,对于一个指针p, 运算p++和p-2都是非法的。
如果p为一个指向一个数值类型值的指针,*p++将被编译器认为是合法的并且等价于(*p)++。 换句话说,解引用操作符*的优先级都高于自增++和自减--操作符。
一个指针值不能和其它任一指针类型的值进行比较
Go指针值是支持(使用比较运算符==和!=)比较的。 但是,两个指针只有在下列任一条件被满足的时候才可以比较:
这两个指针的类型相同。
其中一个指针可以被隐式转换为另一个指针的类型。换句话说,这两个指针的类型的底层类型必须一致并且至少其中一个指针类型为无名的(考虑结构体字段的标签)。
其中一个并且只有一个指针用类型不确定的nil标识符表示。
一个指针类型的值不能被随意转换为另一个指针类型
在Go中,只有如下某个条件被满足的情况下,一个类型为T1的指针值才能被显式转换为另一个指针类型T2:
类型T1和T2的底层类型必须一致(忽略结构体字段的标签)。 特别地,如果类型T1和T2中只要有一个是无名类型并且它们的底层类型一致(考虑结构体字段的标签),则此转换可以是隐式的。
类型T1和T2都为无名类型并且它们的基类型的底层类型一致(忽略结构体字段的标签)。
Go指针的限制是可以被打破的
unsafe标准库包中提供的非类型安全指针(unsafe.Pointer)机制可以被用来打破上述Go指针的安全限制。 unsafe.Pointer类型类似于C语言中的void*。 但是,通常地,非类型安全指针机制不推荐在Go日常编程中使用。
相关文章:
Go 指针
指针在编程中,一个内存地址用来定位一段内存。通常地,一个内存地址用一个操作系统原生字(native word)来存储。 一个原生字在32位操作系统上占4个字节,在64位操作系统上占8个字节。 所以,32位操作系统上的理…...
shardingsphere5.1.1分表分库yaml配置 自定义策略
前言通过阅读官方稳定给出示例 https://shardingsphere.apache.org/document一、基本配置示例spring:sharding:datasource:names: ds0, ds1ds0:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/db0username: rootpassword: rootds1:driver-class-na…...
“探索未来:VR全景直播技术引领新媒体时代”
随着虚拟现实技术的不断发展,VR全景直播已经成为了越来越受欢迎的直播形式。VR全景直播可以让观众通过虚拟现实设备亲临直播现场,享受身临其境的观看体验。VR全景直播是什么? VR全景直播是虚拟现实技术和直播的结合。相对于传统直播ÿ…...
Spring Cloud(微服务)学习篇(六)
Spring Cloud(微服务)学习篇(六) 2 Sentinel实现流量规则(控制台版) 2.1 变更pom.xml(shop-user-server项目)代码 2.1.1 加入如下依赖 <!--熔断限流--> <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-…...
MATLAB-Scatter3-三维散点图投影至XYZ三个平面
MATLAB-Scatter3函数可以绘制立体的三维散点图,但有时候需要在该立体图中分析X-Y-Z三者的关系,即1副图呈现出4个信息,XYZ综合信息、XY信息、XZ信息、YZ信息。现有的Scatter3无法实现该功能,本文可实现Scatter3三维立体散点图在三个…...
Unity/C#------委托与事件(一篇文章彻底搞懂...)
一:委托 所有的代码语言创造者母语都是英语,我们从英语翻译到中文的过程中难免会存在一些不太能还原本意的词,比如我之前一直不理解构造函数和析构函数,只知道这俩货作用相反,直到我看到了它的英文意思,Con…...
别再为 Jenkins 安装烦恼,Docker 帮你轻松解决
前言 大家好,又见面了,我是沐风晓月,本文收录与云原生相关的专栏,以下是我的简介: 🏠个人主页:我是沐风晓月 🧑个人简介:大家好,我是沐风晓月,双…...
汇编语言程序设计(一)
前言 在学习汇编语言之前,我们应该要知道汇编语言他是一门怎么样的语言。汇编语言是直接工作在硬件上的一门编程语言,学习汇编语言之前最好先了解一下计算机硬件系统的结构和工作原理。学习汇编语言的重点是学习如何利用硬件系统的编程结构和指令集进而…...
【uni-app教程】四、UniAPP 路由配置及页面跳转
四、UniAPP 路由配置及页面跳转 (1) 路由配置 uni-app页面路由为框架统一管理,开发者需要在pages.json里配置每个路由页面的路径及页面样式。类似小程序在 app.json 中配置页面路由一样。所以 uni-app 的路由用法与 Vue Router 不同,如仍希望采用 Vue …...
ROS从入门到精通系列(二十八)-- ROS控制器图形化界面开发
ROS (Robot Operating System, 机器人操作系统) 作为机器人软件中的通信及控制中间件,提供一系列程序库和工具以帮助软件开发者创建机器人应用软件。它提供了硬件抽象、设备驱动、函数库、可视化工具、消息传递和软件包管理等诸多功能。ROS遵循BSD开源许可协议。 随着机器人智…...
Submodule命令:android如何将自己项目中的某个Module作为gitlab中第三方公共库
一、创建远程公共库 1、Android Studio创建本地仓库 创建一个新的module 在新建module中添加代码(此处示例代码) 右击新建的module,打开新建module的命令行界面, 因为我们只上传这个module的代码,而不是整个项目的代码 命令行中输入以下命令…...
MySQL索引事务
1.索引1.1概念索引是一种特殊的文件,包含着对数据表里所有记录的引用指针。可以对表中的一列或多列创建索引,并指定索引的类型,各类索引有各自的数据结果实现。(这里只用通俗的语言和图片进行介绍)1.2作用数据库中的表…...
ISO27001信息安全管理体系认证
ISO信息安全管理体系认证 一、什么是ISO信息安全管理体系认证? ISO是信息安全管理体系认证,是由国际标准化组织(ISO)采纳英国标准协会BS-2标准后实施的管理体系,成为了“信息安全管理”的国际通用语言,企…...
Linux应用GUI开发C++ 之gtkmm4(1)
目录概述GTKgtkmm安装gtkmm4hello,worldcodelite配置代码解释概述 GTK GTK是一个小部件工具包。GTK创建的每个用户界面都由小部件组成。这是在C语言中使用GObject实现的,GObject是一个面向对象的C语言框架。窗口小部件是主容器。然后通过向窗口中添加按钮、下拉菜…...
选课系统的设计与实现
技术:Java等摘要:目前国内各高校的规模越来越大,进而造成教师教学管理等工作量日趋加大。然而,现代教育的信息化、网络化已经成为教育发展的一个重要方向,同时也为解决高校教学管理效率低下的现状,使管理突…...
关于安卓的一些残缺笔记
安卓笔记Android应用项目的开发过程Android的调试Android项目文档结构Intent的显式/隐式调用Activity的生命周期1个Activity界面涉及到生命周期的情况2个Activity界面涉及到生命周期的情况Android布局的理论讲解Activity界面布局ContentProvider是如何实现数据共享Android整体架…...
MySQL 中的锁有哪些类型,MySQL 中加锁的原则
锁的类型MySQL 找那个根据加锁的范围,大致可以分成全局锁,表级锁和行级锁。全局锁全局锁,就是对整个数据库加锁。加锁flush tables with read lock解锁unlock tables全局锁会让整个库处于只读状态,之后所有的更新操作都会被阻塞&a…...
Winform中操作Sqlite数据增删改查、程序启动时执行创建表初始化操作
场景 Sqlite数据库 SQLite是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。 它是一个零配置的数据库,这意味着与其他数据库不一样,您不需要在系统中配置。 就像其他数据库,SQLite 引擎不…...
2023最新版本RabbitMQ下载安装教程
一、RabbitMQ简介 RabbitMQ 是一个由 Erlang 语言开发的 AMQP 的开源实现。主要用于在进程、应用程序和服务器之间交换数据,可以通过插件支持进行扩展,支持许多协议,并提供高性能、可靠性、集群和高可用队列。 AMQP :Advanced Me…...
如何使用码匠连接 Elasticsearch
目录 在码匠中集成 Elasticsearch 在码匠中使用 Elasticsearch 关于码匠 Elasticsearch 是一个开源的分布式搜索和分析引擎,常用于处理大规模数据集的搜索、实时数据分析和数据挖掘任务。它支持多种数据源,包括关系型数据库(如 MySQL、Pos…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
