别乱用了,用新的。Go SliceHeader 和 StringHeader 将会被废弃!

news2024/11/16 15:53:08

大家好,我是煎鱼。

Go 语言中有个很经典的 (Slice|String)Header,经常出现在大家视野中,为此我写了《Go SliceHeader 和 StringHeader,你知道吗?》给大家介绍,避免被面试官卷到。

以重点来讲,SliceHeader 是 Slice(切片)的运行时表现;StringHeader 是 String(字符串)的运行时表现。

背景

为什么这两个运行时结构体受到了那么多的关注呢?是因为常被用于如下场景:

  • 将 []byte 转换为 string。

  • 将 string 转换为 []byte。

  • 抓取数据指针(data pointer)字段用于 ffi 或其他用途。

  • 将一种类型的 slice 转换为另一种类型的 slice。

常见案例,可见如下代码:

s := "脑子进煎鱼了?重背面试题(doge"
h := (*reflect.StringHeader)(unsafe.Pointer(&s))

又或是自己构造一个:

unsafe.Pointer(&reflect.StringHeader{
  Data: uintptr(unsafe.Pointer(&s.Data[0])),
  Len:  int(s.Size),
 })

似乎看起来没什么问题,所以在业内打开了一种新的姿势。那就是借助 (String|Slice) Header 来实现零拷贝的 string 到 bytes 的转换,得到了广大开发者的使用。毕竟谁都想性能高一点。

如下转换代码:

func main() {
 s := "脑子进煎鱼了"
 v := string2bytes1(s)
 fmt.Println(v)
}

func string2bytes1(s string) []byte {
 stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))

 var b []byte
 pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
 pbytes.Data = stringHeader.Data
 pbytes.Len = stringHeader.Len
 pbytes.Cap = stringHeader.Len

 return b
}

当然,还有更多基于 Header 自己写的转换,甚至写错写到泄露没法被 GC 的,又或是抛出 throw 致命错误查了几周的。

问题

今年 Go 团队进行了讨论,通过分析、搜索发现 reflect.SliceHeaderreflect.StringHeader 在业内经常被滥用,且使用不方便,很容易出错(要命的是很隐性的那种)。

GitHub 搜索发现大量用户案例:

ad726c6fabbfb23820f58ca865e2be6f.png

这个坑也在于,SliceHeader 和 StringHeader 的 Data 字段(后称数据指针):

type StringHeader struct {
   Data uintptr
   Len  int
}

类型是 uintptr不是 unsafe.Pointer。设什么都可以,灵活度过于高,非常容易搞出问题。

Go1.20 新特性

在 Go1.20 起,在 unsafe 标准库新增了 3 个函数来替代前面这两个类型的使用。希望能够进一步标准化,并提供额外的类型安全。

d107ba63626404d9cadda84aeb5d7bac.png

如下函数签名:

  • func String(ptr *byte, len IntegerType) string:根据数据指针和字符长度构造一个新的 string。

  • func StringData(str string) *byte:返回指向该 string 的字节数组的数据指针。

  • func SliceData(slice []ArbitraryType) *ArbitraryType:返回该 slice 的数据指针。

新版本的用法将会变成:

func StringToBytes(s string) []byte {
    return unsafe.Slice(unsafe.StringData(s), len(s))
}

func BytesToString(b []byte) string {
    return unsafe.String(&b[0], len(b))
}

以往常用的 reflect.SliceHeaderreflect.StringHeader 将会被标注为被废弃

如下图:

7f5e7ab1197fea1a0ad0d544f7bab623.png

这两个类型老版本中一直被标记为不稳定、不可靠。

以后记得换用法了。

总结

StringHeader 和 SliceHeader 在工作中的底层工具包在前两年非常常见,如果是一个积累比较久的项目可能在内部都偷偷引用了,目的就是为了让自己的性能跑分更优一些。

但是其较大的自由度,带来了过大的类型不安全。因此我在工作中也遇到有人用到莫名其妙抛致命错误,最后只能用排除法去查是哪里的锅。

在新版本 Go1.20 中,Go 官方引入了这几个新函数。能够进一步声明这是 unsafe 的,也能提供一点点的类型安全检查。

当然,新版本后,爱问这几个零拷贝的面试官,也得刷新一下知识库了。

推荐阅读

  • Go1.20 中两个关于 Time 的更新,终于不用背 2006-01-02 15:04:05 了!

  • 打脸了兄弟们,Go1.20 arena 来了!

  • Go 十年了,终于想起要统一 log 库了!

关注和加煎鱼微信,

一手消息和知识,拉你进技术交流群👇

1838e3129b767faeeac8049c8b486242.jpeg

a2b60fd56de43f7671c027e9a5ae167f.png

你好,我是煎鱼,出版过 Go 畅销书《Go 语言编程之旅》,再到获得 GOP(Go 领域最有观点专家)荣誉,点击蓝字查看我的出书之路

日常分享高质量文章,输出 Go 面试、工作经验、架构设计,加微信拉读者交流群,和大家交流!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Alibaba送给开发人员的“礼物”:Java架构成长笔记,深入内核,拒绝蒙圈

提起阿里,行外人联想到的关键词无非是“交易”、“淘宝”、“支付宝”,但对于程序员来说,阿里庞大的技术体系才是最吸引人的。实际上阿里作为国内一线互联网公司的头把交椅,内部的技术体系和发展都是备受关注的,对于程…

【javaScript总结归纳】字符串常用方法总结

前言 在js中我们对字符串进行一部分截取,可以使用slice()函数截取,也可以直接用substring()函数来截取,但是截取也有可能出bug const str小𠮷和小𧨁今天吃了50块钱的KFC console.log(str.slice(0,5)); 可以在控制台看…

评估EtherCAT从站节点解决方案

本系列博客文章的第1部分介绍了用于C2000™微控制器的EtherCAT从站堆栈解决方案的市场机遇,以及从站堆栈开发快速入门的三个阶段指南。第2部分详细说明了TIC2000 MCU EtherCAT实施的特点和优势。第3部分分别介绍了使用EtherCAT从站和C2000 Delfino MCU controlCARD套…

Linux【windows使用xshell连接本地虚拟机】【Mac使用terminal连接本地虚拟机】

文章目录对于本地虚拟机的配置使用Mac的terminal的ssh连接本地虚拟机windows使用xshell连接本地虚拟机对于本地虚拟机的配置 IP地址和子网掩码。 在虚拟机中使用ping命令判断虚拟机到宿主机是否是连通的。(不通的话,关闭Windows防火墙,再试一…

python+pyhyper实现识别图片中的车牌号

背景 最近领导给布置了一个基于图片识别车牌号的工具开发任务,然后就去研究实现逻辑,自己根据opencv写了一个小demo,发现不仅速度慢而且成功率极低。然后,就找到了Hyperlpr开源项目。 环境搭建 排雷1:有教程说在git…

动态内存管理易错点+分析例题

复习一下: 常见的错误: 1.可能返回的是空指针 2.对动态开辟的内存越界访问 3.非动态开辟内存却用free释放 4.使用free释放动态开辟内存的一部分 5.free多次释放 如果加了pNULL的话 free(p)相当于啥也不干 程序起码不会崩掉 6.动…

RabbitMQ、RocketMQ、Kafka延迟队列实现

延迟队列在实际项目中有非常多的应用场景,最常见的比如订单未支付,超时取消订单,在创建订单的时候发送一条延迟消息,达到延迟时间之后消费者收到消息,如果订单没有支付的话,那么就取消订单。 那么&#xf…

Proteus8仿真:51单片机IrLink红外发送加接受模块的使用

51单片机IrLink红外的使用元器件原理图部分代码单片机1发送main.c单片机2接受main.c工程文件元器件 元器件名称51单片机AT89C51红外收发IRLINK按键BUTTON发光二极管LED-RED时钟激励源DCLOCK与门74LS08示波器 原理图部分 关于IRLINK的使用: 在Proteus上就是一个红外…

数据中台选型前必读(七):解读数据服务的四大关键技术

在前面的文章中,我们介绍了“数据服务”对于“数据中台”的重要性,并讲解了数据服务解决的问题及其核心功能,在这个系列的最终篇我们展开聊聊数据服务的四大关键技术,然后总结一下数据服务架构的三大关键点,希望对大家…

JSP ssh培训管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 JSP ssh 培训管理系统是一套完善的web设计系统(系统采用ssh框架进行设计开发),对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Mye…

校园打架行为识别检测 yolov7

校园打架行为识别检测系统基于python基于yolov7深度学习框架边缘分析技术,自动对校园、广场等区域进行实时监测,当监测到有人打架斗殴时,系统立即抓拍存档语音提醒,并将打架行为回传给学校后台,提醒及时处理打架情况。…

Word控件Spire.Doc 【超链接】教程(7):在 C#、VB.NET 中的 Word 中创建图像超链接

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下,轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具,专注于创建、编辑、转…

你一定要会的JavaFile

File对象就表示一个路径,可以是文件的路径,也可以是文件夹的路径这个路径可以是存在的,也允许是不存在的File的构造 方法名称说明public File(String pathname)根据文件路径创建文件对象public File(String parent,String child)根据父路径名…

第4章 角色Api控件器的实现与调试

1 自定义管道中间件 1.1 WebApi.Middleware.CorsMiddleware namespace WebApi.Middleware { /// <summary> /// 【跨域访问中间件--类】 /// <remarks> /// 摘要&#xff1a; /// 该管道中间件类主要为了解决在由vue/uni-app前端项目(Cors)访问当前后端项…

你的期待薪资是多少?为什么?

很多人去面试的时候&#xff0c;就像打游戏&#xff0c;过五关斩六将&#xff0c;终于到最后一关了&#xff0c;但是谈薪资的难度堪比打游戏中搞定终级 boss 的难度&#xff0c;真的是太「南」了&#xff0c;好多人都是因为这个问题让自己五味杂陈呀。报高了怕好 offer 失之交臂…

【Call for papers】SIGIR-2023(CCF-A/内容检索/2023年1月31日截稿)

The 46th International ACM SIGIR Conference on Research and Development in Information Retrieval will be held from 23-27 July, 2023 in Taipei. 文章目录1.会议信息2.时间节点3.论文主题1.会议信息 会议介绍&#xff1a; SIGIR是展示新研究成果和展示信息检索新系统和…

Postgresql INDEX HOT 原理与更好的 “玩转” INDEX

随着问问题的同学越来越多&#xff0c;公众号内部私信回答问题已经很困难了&#xff0c;所以建立了一个群&#xff0c;关于各种数据库的问题都可以&#xff0c;目前主要是 POSTGRESQL, MYSQL ,MONGODB ,POLARDB ,REDIS&#xff0c;SQL SERVER 等&#xff0c;期待你的加入&#…

[洛谷]P1996 约瑟夫问题

[洛谷]P1996 约瑟夫问题一、问题描述题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1提示二、思路分析1、算法标签&#xff1a;2、算法分析&#xff1a;三、代码实现1、环形链表2、队列一、问题描述 [洛谷]P1996 约瑟夫问题 题目描述 nnn 个人围成一圈&#xff0c;从…

3.Spark 操作

基于centos7 ,hadoop2.7.3, spark-2.4.4-bin-hadoop2.7.tgz 目录: 一.spark shell二. 读取hdfs文件三.Idea中编写wordcount一.spark shell 在spark shell中编写wordcount程序读取本地文件 1、准备数据源(创建目录,创建文件) 2.代码: --注意修改文件地址-- sc.textF…

【QT开发笔记-基础篇】| 第五章 绘图QPainter | 5.8 画刷设置

本节对应的视频讲解&#xff1a;B_站_视_频 https://www.bilibili.com/video/BV1A44y1Z7vz 本节讲解画刷的设置&#xff0c;包括画刷的颜色和样式 画刷设置完后&#xff0c;就可以把该画刷设置给 QPainter 了 1. 相关 API 1.1 画刷颜色 // 获取和设置画刷的颜色 const QCo…