Go 常量为什么只支持基本数据类型?

大家好,我是煎鱼。

相信大家在接触 Go 这门编程语言时,就会学到常量这个知识点。

各大编程语言会教你,常量是不可变变量的一种类型。只要定义了常量,你就可以安心的用他。不用担心值在哪里就被程序莫名奇妙的给改了。

常量的使用例子

如下例子:

const s string = "脑子进煎鱼了"func main() {fmt.Println(s)const n = 500000000const d = 3e20 / nfmt.Println(d)fmt.Println(int64(d))fmt.Println(math.Sin(n))
}

输出结果:

脑子进煎鱼了
6e+11
600000000000
-0.28470407323754404

你可能会发现一个奇怪的点。那就是例子里都是基本的数据类型。那能不能用复杂点的数据类型呢,例如 Go 里比较经典的切片。

如果是用 var 声明:

var s = []string{"摸", "煎", "鱼"}func main() {fmt.Println(s)
}

正常输出:[摸 煎 鱼]

如果是用 const 声明:

const s = []string{"摸", "煎", "鱼"}

将会报错:

./prog.go:7:11: []string{…} (value of type []string) is not constant

因为在 Go 中,仅支持字符、字符串、布尔和数值类型的常量。这和其他编程语言间多多少少还是有点不一样的。

为什么不支持更多类型

为什么在 Go 中常量只支持这几种基础类型,为什么没法支持复杂类型,或是所有类型?

这是非常 “奇怪” 的。毕竟 PHP 都能支持:

class MyClass
{const ABC = array('A', 'B', 'C');const A = '1';const B = '2';const C = '3';const NUMBERS = array(self::A,self::B,self::C,);}

这又是出于什么缘由?

已有 10 年老提案

我认真翻阅了 Go issues 等相关资料,终于发现竟然在 2013 年(10 年前),就已经有人提出过这个提案:

28e111623aecd705363d752503a36ee4.png

提出者 @RickySeltzer,认为:

var each1 = []byte{'e', 'a', 'c', 'h'}

可以正常运行。

const each2 = []byte{'e', 'a', 'c', 'h'}

不行,直接报错:prog.go:7: const initializer []byte literal is not a constant

他认为这就是 Go 语言规范和设计上的缺陷,得改,得支持!

拒绝的论据是什么

对此也有各种争论,老大哥 @Robert Griesemer,10 年前已 在为 Go 贡献,现在依然还在...他对 Go 常量只支持基本类型这个设计给出了定论。

基于如下原因:

  • 首先这不是语言的缺陷,也不是设计的缺陷。Go 语言的常量是故意设计成只支持基本类型。

  • 基本类型到复杂类型的改变,这种变化的影响比我们看到的要深远得多。需要考虑很多问题。

    • 常量 channel、常量指针、常量 maps、常量 slice 都要支持吗?

    • 先支持常量 array 和 常量 struct?

    • 要支持到什么程度,以什么来作为标准决定?

  • 设计上,Go 团队期望类型系统(包括常量的含义)相对简单,以免在编译时出现问题。

    • 常量更多类型的支持,会增加复杂性。不清楚这样做的好处是否值得(ROI)。

    • 常量是否可以寻址?const 数组的元素本身必须是 const 吗?

汇总一下,潜台词就是:

  1. 设计如下:常量只支持基本类型,是 Go 设计上就是这么决定的。

  2. ROI 要衡量一下:没有支持更多的复杂类型,是认为好处不多。也没有想清楚这块的缘由。

  3. 少即是多:类型系统要保持少即是多(less is more)。

实战中的骚操作

在相关提案的 issues 中看到欧神(@Changkun Ou)也参与了讨论,他例举了一个常量的经典骚操作。

代码如下:

- const ErrVerification = errors.New("crypto/rsa: verification error")
+ var ErrVerification = errors.New("crypto/rsa: verification error")

在对应的 Go 工程中可能是这么使用:

import "cropto/rsa"
func init() {rsa.ErrVerification = nil
}

这个场景我还真见过,一开始想定义 const,结果不支持。只能被迫 var。这不,就开天窗了。

总结

Go 核心团队在综合衡量 ROI 后,认为常量支持更多的类型在可预见的未来不会改变。因为将常量的概念扩展到基本类型之外将是一个重大变化,会产生各种影响。

在此刻(Go1)改变语言的门槛非常高,需要有明确的定义,要有完整的提案以及对成本和效益等的详细分析。

如果出现,只可能在未来的 Go2。但结合 rsc 最新的结论,没有 Go2 的话,那如果未来真的做,那就是通过 GODEBUG 和 go.mod 的 go 版本号来实现了。

常量更多类型的支持,虽然已经提出了 10 年。但目前 Go 核心团队推进乏力,想必,可能还要个 5 年吧。

推荐阅读

  • 互联网公司裁员的预兆和手段

  • 又有新功能!Go 将有生成新模板的 gonew 工具链

  • Go1.21 那些事:泛型库、for 语义变更、统一 log/slog、WASI 等新特性,你知道多少?

关注和加煎鱼微信,

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

100b32168d09b15b9c01be546fcd2e60.jpeg

b750269e890ba4cc39301b076bf9a184.png

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Adobe Acrobat Reader界面改版 - 解决方案

问题 日期:2023年9月 Adobe Acrobat Reader下文简称Adobe PDF Reader,此软件会自动进行更新,当版本更新至2023.003.20284版本后。 软件UI界面会大改版:书签页变成了右边、工具栏变到了左边、缩放按钮变到了右下角,如…

Linux如何安装MySQL

Linux安装MySQL5.7 1、下载 官网下载地址:http://dev.mysql.com/downloads/mysql/ 2、复制下面几个文件 3、检查当前系统是否安装过mysql、检查当前mysql依赖环境、检查/tmp文件夹权限 1)检查当前系统是否安装过mysql,执行安装命令前&am…

4.zigbee开发,传感器网络管理进阶(网状和树状拓扑),zigbee的ADC

一。zigbee的串口 1.串口通信的基本概念 (1)同步通信与异步通信 同步通信: 一般情况下同步通信指的是通信双方根据同步信号进行通信的方式。比如通信双方有一个共同的时钟信号,通讯中通常双方会统一规定在时钟信号的上升沿…

核心实验21_BGP高级(了解)(配置略)_ENSP

项目场景: 核心实验21_BGP基础_ENSP 通过bgp实现省市互通。 实搭拓扑图: 具体操作: 其他基础配置略(接口地址,ospf) 1.BGP邻居建立: R1: [R1]bgp 200 [R1-bgp]peer 10.2.2.2 as-number 200 …

USB接口针式打印机

1 针式打印机原理 - 针式打印机16针是纵向排列,每次打印垂直的16bit,然后右移一bit,继续下列打印;字节的MSB表示最上面的点,字节LSB表示最下面的点 - 由于汉字字模的点阵是横向排列的,而提供给打印头的信息…

【PHY】3GPP UE能力类别的变化

博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持! 博主链接 本人就职于国际知名终端厂商,负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。 博客…

《PostgreSQL与MySQL:详细对比与分析》

🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🐅🐾猫头虎建议程序员必备技术栈一览表📖: 🛠️ 全栈技术 Full Stack: &#x1f4da…

sql server 触发器的使用

看数据库下的所有触发器及状态 SELECT a.name 数据表名 , sysobjects.name AS 触发器名 , sysobjects.crdate AS 创建时间 , sysobjects.info , sysobjects.status FROM sysobjects LEFT JOIN ( SELECT * FROM sysobjects WHERE xtype U ) AS a ON sysobjects.parent_obj a.…

请求与响应以及REST风格

目录 请求与响应请求参数参数传递 五种类型参数传递普通参数POJO数据类型嵌套POJO类型参数数组类型参数集合类型参数 JSON数据传输参数JSON普通数组JSON对象数据JSON对象数组知识点1:EnableWebMvc知识点2:RequestBodyRequestBody与RequestParam区别日期类…

js中添加屏蔽F12 审查元素、屏蔽开发者工具、屏蔽右键菜单、屏蔽剪切、屏蔽选中操作

在看某个网站时,看到一段话想复制一下,结果复制不了。想打开F12看看元素进行复制,也不行,没有反应。最后通过打开开发者工具看看,结果一打开就跳到about:blank。 看到这操作一脸懵逼,小样的,还有…

【VS2022】调试

F9 创建或取消断点 ctrlF9 禁用断点 F5 开始调试(到断点处停下来) F10 逐过程(不进入函数) F11 逐语句 F5、F10、F11都可以直接进入调试 【调试】->【窗口】->【监视】,输入变量就可以观察到变量的值。 …

第 2 章 线性表 (线性表的单链表存储结构实现)

1. 背景说明 2. 示例代码 1) status.h /* DataStructure 预定义常量和类型头文件 */#ifndef STATUS_H #define STATUS_H#define CHECK_NULL(pointer) if (!(pointer)) { \printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_PT…