当前位置: 首页 > news >正文

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。

如何获取一个指针值?

有两种方式来得到一个指针值:

  1. 我们可以用内置函数new来为任何类型的值开辟一块内存并将此内存块的起始地址做为此值的地址返回。 假设T是任一类型,则函数调用new(T)返回一个类型为*T的指针值。 存储在返回指针值所表示的地址处的值(可被看作是一个匿名变量)为T的零值。

  1. 我们也可以使用前置取地址操作符&来获取一个可寻址的值的地址。 对于一个类型为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 指针

指针在编程中&#xff0c;一个内存地址用来定位一段内存。通常地&#xff0c;一个内存地址用一个操作系统原生字&#xff08;native word&#xff09;来存储。 一个原生字在32位操作系统上占4个字节&#xff0c;在64位操作系统上占8个字节。 所以&#xff0c;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全景直播技术引领新媒体时代”

随着虚拟现实技术的不断发展&#xff0c;VR全景直播已经成为了越来越受欢迎的直播形式。VR全景直播可以让观众通过虚拟现实设备亲临直播现场&#xff0c;享受身临其境的观看体验。VR全景直播是什么&#xff1f; VR全景直播是虚拟现实技术和直播的结合。相对于传统直播&#xff…...

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函数可以绘制立体的三维散点图&#xff0c;但有时候需要在该立体图中分析X-Y-Z三者的关系&#xff0c;即1副图呈现出4个信息&#xff0c;XYZ综合信息、XY信息、XZ信息、YZ信息。现有的Scatter3无法实现该功能&#xff0c;本文可实现Scatter3三维立体散点图在三个…...

Unity/C#------委托与事件(一篇文章彻底搞懂...)

一&#xff1a;委托 所有的代码语言创造者母语都是英语&#xff0c;我们从英语翻译到中文的过程中难免会存在一些不太能还原本意的词&#xff0c;比如我之前一直不理解构造函数和析构函数&#xff0c;只知道这俩货作用相反&#xff0c;直到我看到了它的英文意思&#xff0c;Con…...

别再为 Jenkins 安装烦恼,Docker 帮你轻松解决

前言 大家好&#xff0c;又见面了&#xff0c;我是沐风晓月&#xff0c;本文收录与云原生相关的专栏&#xff0c;以下是我的简介&#xff1a; &#x1f3e0;个人主页&#xff1a;我是沐风晓月 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是沐风晓月&#xff0c;双…...

汇编语言程序设计(一)

前言 在学习汇编语言之前&#xff0c;我们应该要知道汇编语言他是一门怎么样的语言。汇编语言是直接工作在硬件上的一门编程语言&#xff0c;学习汇编语言之前最好先了解一下计算机硬件系统的结构和工作原理。学习汇编语言的重点是学习如何利用硬件系统的编程结构和指令集进而…...

【uni-app教程】四、UniAPP 路由配置及页面跳转

四、UniAPP 路由配置及页面跳转 (1) 路由配置 uni-app页面路由为框架统一管理&#xff0c;开发者需要在pages.json里配置每个路由页面的路径及页面样式。类似小程序在 app.json 中配置页面路由一样。所以 uni-app 的路由用法与 Vue Router 不同&#xff0c;如仍希望采用 Vue …...

ROS从入门到精通系列(二十八)-- ROS控制器图形化界面开发

ROS (Robot Operating System, 机器人操作系统) 作为机器人软件中的通信及控制中间件,提供一系列程序库和工具以帮助软件开发者创建机器人应用软件。它提供了硬件抽象、设备驱动、函数库、可视化工具、消息传递和软件包管理等诸多功能。ROS遵循BSD开源许可协议。 随着机器人智…...

Submodule命令:android如何将自己项目中的某个Module作为gitlab中第三方公共库

一、创建远程公共库 1、Android Studio创建本地仓库 创建一个新的module 在新建module中添加代码(此处示例代码) 右击新建的module&#xff0c;打开新建module的命令行界面&#xff0c; 因为我们只上传这个module的代码&#xff0c;而不是整个项目的代码 命令行中输入以下命令…...

MySQL索引事务

1.索引1.1概念索引是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针。可以对表中的一列或多列创建索引&#xff0c;并指定索引的类型&#xff0c;各类索引有各自的数据结果实现。&#xff08;这里只用通俗的语言和图片进行介绍&#xff09;1.2作用数据库中的表…...

ISO27001信息安全管理体系认证

​ISO信息安全管理体系认证 一、什么是ISO信息安全管理体系认证&#xff1f; ISO是信息安全管理体系认证&#xff0c;是由国际标准化组织&#xff08;ISO&#xff09;采纳英国标准协会BS-2标准后实施的管理体系&#xff0c;成为了“信息安全管理”的国际通用语言&#xff0c;企…...

Linux应用GUI开发C++ 之gtkmm4(1)

目录概述GTKgtkmm安装gtkmm4hello,worldcodelite配置代码解释概述 GTK GTK是一个小部件工具包。GTK创建的每个用户界面都由小部件组成。这是在C语言中使用GObject实现的&#xff0c;GObject是一个面向对象的C语言框架。窗口小部件是主容器。然后通过向窗口中添加按钮、下拉菜…...

选课系统的设计与实现

技术&#xff1a;Java等摘要&#xff1a;目前国内各高校的规模越来越大&#xff0c;进而造成教师教学管理等工作量日趋加大。然而&#xff0c;现代教育的信息化、网络化已经成为教育发展的一个重要方向&#xff0c;同时也为解决高校教学管理效率低下的现状&#xff0c;使管理突…...

关于安卓的一些残缺笔记

安卓笔记Android应用项目的开发过程Android的调试Android项目文档结构Intent的显式/隐式调用Activity的生命周期1个Activity界面涉及到生命周期的情况2个Activity界面涉及到生命周期的情况Android布局的理论讲解Activity界面布局ContentProvider是如何实现数据共享Android整体架…...

MySQL 中的锁有哪些类型,MySQL 中加锁的原则

锁的类型MySQL 找那个根据加锁的范围&#xff0c;大致可以分成全局锁&#xff0c;表级锁和行级锁。全局锁全局锁&#xff0c;就是对整个数据库加锁。加锁flush tables with read lock解锁unlock tables全局锁会让整个库处于只读状态&#xff0c;之后所有的更新操作都会被阻塞&a…...

Winform中操作Sqlite数据增删改查、程序启动时执行创建表初始化操作

场景 Sqlite数据库 SQLite是一个进程内的库&#xff0c;实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。 它是一个零配置的数据库&#xff0c;这意味着与其他数据库不一样&#xff0c;您不需要在系统中配置。 就像其他数据库&#xff0c;SQLite 引擎不…...

2023最新版本RabbitMQ下载安装教程

一、RabbitMQ简介 RabbitMQ 是一个由 Erlang 语言开发的 AMQP 的开源实现。主要用于在进程、应用程序和服务器之间交换数据&#xff0c;可以通过插件支持进行扩展&#xff0c;支持许多协议&#xff0c;并提供高性能、可靠性、集群和高可用队列。 AMQP &#xff1a;Advanced Me…...

如何使用码匠连接 Elasticsearch

目录 在码匠中集成 Elasticsearch 在码匠中使用 Elasticsearch 关于码匠 Elasticsearch 是一个开源的分布式搜索和分析引擎&#xff0c;常用于处理大规模数据集的搜索、实时数据分析和数据挖掘任务。它支持多种数据源&#xff0c;包括关系型数据库&#xff08;如 MySQL、Pos…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

Kafka入门-生产者

生产者 生产者发送流程&#xff1a; 延迟时间为0ms时&#xff0c;也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于&#xff1a;异步发送不需要等待结果&#xff0c;同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

Linux nano命令的基本使用

参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时&#xff0c;显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...