返回顶部
首页 > 资讯 > 后端开发 > GO >Golang无类型常量问题怎么解决
  • 703
分享到

Golang无类型常量问题怎么解决

2023-07-05 14:07:54 703人浏览 安东尼
摘要

今天小编给大家分享一下golang无类型常量问题怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。这个问题是很常见的:p

今天小编给大家分享一下golang无类型常量问题怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

    这个问题是很常见的:

    package main import "fmt" type S string const (    A S = "a"    B   = "b"    C   = "c") func output(s S) {    fmt.Println(s)} func main() {    output(A)    output(B)    output(C)}

    这段代码能正常编译并运行,能有什么问题?这里我就要提示你一下了,B和C的类型是什么?

    你会说他们都是S类型,那你就犯了第一个错误,我们用发射看看:

    fmt.Println(reflect.TypeOf(any(A)))fmt.Println(reflect.TypeOf(any(B)))fmt.Println(reflect.TypeOf(any(C)))

    输出是:

    main.S
    string
    string

    惊不惊喜意不意外,常量的类型是由等号右边的值推导出来的(iota是例外,但只能处理整型相关的),除非你显式指定了类型。

    所以在这里B和C都是string。

    那真正的问题来了,正如我在这篇所说的,从原类型新定义的类型是独立的类型,不能隐式转换和赋值给原类型。

    所以这样的代码就是错的:

    func output(s S) {    fmt.Println(s)} func main() {    var a S = "a"     output(a)}

    编译器会报错。然而我们最开始的复现代码是没有报错的:

    const (    A S = "a"    B   = "b"    C   = "c") func output(s S) {    fmt.Println(s)}

    output函数只接受S类型的值,但我们的B和C都是string类型的,为什么这里可以编译通过还正常运行了呢?

    这就要说到Golang的坑点之一——无类型常量了。

    什么是无类型常量

    这个好理解,定义常量时没指定类型,那就是无类型常量,比如:

    const (    A S = "a"    B   = "b"    C   = "c")

    这里A显式指定了类型,所以不是无类型常量;而B和C没有显式指定类型,所以就是无类型常量(untyped constant)。

    无类型常量的特性

    无类型常量有一些特性和其他有类型的常量以及变量不一样,得单独讲讲。

    默认的隐式类型

    正如下面的代码里我们看到的:

    const (    A = "a"    B = 1    C = 1.0) func main() {    fmt.Println(reflect.TypeOf(any(A))) // string    fmt.Println(reflect.TypeOf(any(B))) // int    fmt.Println(reflect.TypeOf(any(C))) // float64}

    虽说我们没给这些常量指定某个类型,但他们还是有自己的类型,和初始化他们的字面量的默认类型相应,比如整数字面量是int,字符串字面量是string等等。

    但只有一种情况下他们才会表现出自己的默认类型,也就是在上下文中没法推断出这个常量现在应该是什么类型的时候,比如赋值给空接口。

    类型自动匹配

    这个名字不好,是我根据它的表现起的,官方的名字叫Representability,直译过来是“代表性”。

    看下这个例子:

    const delta = 1 // untyped constant, default type is intvar num int64num += delta

    如果我们把const换成var,代码无法编译,会爆出这种错误:invalid operation: num + delta (mismatched types int64 and int)。

    但为什么常量可以呢?这就是Representability或者说类型自动匹配在捣鬼。

    按照官方的解释:如果一个无类型常量的值是一个类型T的有效值,那么这个常量的类型就可以是类型T。

    举个例子,int8类型的所有合法的值是[-128, 127),那么只要值在这个范围内的整数常量,都可以被转换成int8。

    字符串类型同理,所有用字符串初始化的无类型常量都可以转换成字符串以及那些基于字符串创建的新类型。

    这就解释了开头那段代码为什么没问题:

    type S string const (    A S = "a"    B   = "b"    C   = "c") func output(s S) {    fmt.Println(s)} func main() {    output(A) // A 本来就是 S,自然没问题    output(B) // B 是无类型常量,默认类型string,可以表示成 S,没问题    output(C) // C 是无类型常量,默认类型string,可以表示成 S,没问题    // 下面的是有问题的,因为类型自动匹配不会发生在无类型常量和字面量以外的地方    // s := "string"    // output(s)}

    也就是说,在有明确给出类型的上下文里,无类型常量会尝试去匹配那个目标类型T,如果常量的值符合目标类型的要求,常量的类型就会变成目标类型T。例子里的delta的类型就会自动变成int64类型。

    我没有去找为什么golang会这么设计,在c++、rust和Java里常量的类型就是从初始化表达式推导或显式指定的那个类型。

    一个猜测是golang的设计初衷想让常量的行为表现和字面量一样。除了两者都有的类型自动匹配,另一个有力证据是golang里能作为常量的只有那些能做字面类型的类型(字符串、整数、浮点数、复数)。

    无类型常量的类型自动匹配会带来很有限的好处,以及很恶心的坑。

    无类型常量带来的便利

    便利只有一个,可以少些几次类型转换,考虑下面的例子:

    const factor = 2 var result int64 = int64(num) * factor / ( (a + b + c) / factor )

    这样复杂的计算表达式在数据分析和图像处理的代码里是很常见的,如果我们没有自动类型匹配,那么就需要显式转换factor的类型,光是想想就觉得烦人,所以我也就不写显式类型转换的例子了。

    有了无类型常量,这种表达式的书写就没那么折磨了。

    无类型常量的坑

    说完聊胜于无的好处,下面来看看坑。

    一种常见的在golang中模拟enum的方法如下:

    type ConfigType string const (    CONFIG_XML ConfigType = "XML"    CONFIG_JSON = "jsON")

    发现上面的问题了吗,没错,只有CONFIG_XML是ConfigType类型的!

    但因为无类型常量有自动类型匹配,所以你的代码目前为止运行起来一点问题也没有,这也导致你没发现这个缺陷,直到:

    // 给enum加个方法,现在要能获取常量的名字,以及他们在配置数组里的indextype ConfigType string func (c ConfigType) Name() string {    switch c {    case CONFIG_XML:        return "XML"    case CONFIG_JSON:        return "JSON"    }    return "invalid"} func (c ConfigType) Index() int {    switch c {    case CONFIG_XML:        return 0    case CONFIG_JSON:        return 1    }    return -1}

    目前为止一切安好,然后代码炸了:

    fmt.Println(CONFIG_XML.Name())fmt.Println(CONFIG_JSON.Name()) // !!! error

    编译器不乐意,它说:CONFIG_JSON.Name undefined (type untyped string has no field or method Name)。

    为什么呢,因为上下文里没明确指定类型,fmt.Println的参数要求都是any,所以这里用了无类型常量的默认类型。当然在其他地方也一样,CONFIG_JSON.Name()这个表达式是无法推断出CONFIG_JSON要匹配成什么类型的。

    这一切只是因为你少写了一个类型。

    这还只是第一个坑,实际上因为只要是目标类型可以接受的值,就可以赋值给目标类型,那么出现这种代码也不奇怪:

    const NET_ERR_MESSAGE = "site is unreachable" func doWithConfigType(t ConfigType) doWithConfigType(CONFIG_JSON)doWithConfigType(NET_ERR_MESSAGE) // WTF???

    一不小心就能把错得离谱的参数传进去,如果你没想到这点而做好防御的话,生产事故就理你不远了。

    第一个坑还可以通过把常量定义写全每个都加上类型来避免,第二个就只能靠防御式编程凑活了。

    以上就是“Golang无类型常量问题怎么解决”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网GO频道。

    您可能感兴趣的文档:

    --结束END--

    本文标题: Golang无类型常量问题怎么解决

    本文链接: https://lsjlt.com/news/352177.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    猜你喜欢
    • Golang无类型常量问题怎么解决
      今天小编给大家分享一下Golang无类型常量问题怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。这个问题是很常见的:p...
      99+
      2023-07-05
    • Golang有类型常量和无类型常量的区别
      场景 在 Go 语言中,常量分为有类型常量和无类型常量。 // 有类型常量 const VERSION string = "v1.0.0" // 无类型常量 const RELEA...
      99+
      2023-05-14
      Golang 有类型常量 无类型常量
    • Golang学习之无类型常量详解
      目录什么是无类型常量无类型常量的特性默认的隐式类型类型自动匹配无类型常量带来的便利无类型常量的坑总结因为虽然名字很陌生,但我们每天都在用,每天都有无数潜在的坑被埋下。包括我本人也犯过...
      99+
      2023-03-20
      Golang无类型常量 Golang 常量
    • Golang有类型常量和无类型常量的区别是什么
      本篇内容主要讲解“Golang有类型常量和无类型常量的区别是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Golang有类型常量和无类型常量的区别是什么”吧!场景在 Go 语言中,常量分为有...
      99+
      2023-07-05
    • ASP 变量与数据类型实战案例:解决常见问题
      ...
      99+
      2024-04-02
    • MySQL中布尔类型的常见问题解决
      MySQL中布尔类型的常见问题解决 在MySQL数据库中,布尔类型通常被表示为TINYINT(1),其中0代表false,1代表true。虽然布尔类型看似简单,但在使用过程中也可能会遇...
      99+
      2024-03-15
      布尔类型问题 布尔类型解决
    • 如何使用泛型解决golang中常见问题?
      go 中泛型可解决常见痛点:类型转换:使用泛型函数简化不同类型的转换。数据结构创建:使用泛型类型简化通用数据结构的创建。函数传递:使用泛型函数声明允许传递各种类型的参数。实战案例:通过类...
      99+
      2024-05-04
      golang 泛型 编译错误 键值对
    • Java泛型中类型擦除问题怎么解决
      这篇“Java泛型中类型擦除问题怎么解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java泛型中类型擦除问题怎么解决”文...
      99+
      2023-06-30
    • Golang初学者无法解决问题
      小伙伴们有没有觉得学习Golang很有意思?有意思就对了!今天就给大家带来《Golang初学者无法解决问题》,以下内容将会涉及到,若是在学习中对其中部分知识点有疑问,或许看了本文就能帮到你!问题内容...
      99+
      2024-04-05
    • 无法读取服务器PHP文件mime类型问题怎么解决
      本篇内容主要讲解“无法读取服务器PHP文件mime类型问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“无法读取服务器PHP文件mime类型问题怎么解决”吧!为了解决这个问题,我们需要先...
      99+
      2023-07-06
    • win10怎么解决驱动正常无声音问题
      这篇文章将为大家详细讲解有关win10怎么解决驱动正常无声音问题,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。在声音上右击选择声音问题疑难解答。进行检测问题,稍等片刻。监测完了之后会给你详细的问题出现的地...
      99+
      2023-06-28
    • golang中包无法引入问题解决
      目录前言问题背景问题现象问题解决1、强制开启GO111MODULE2、切换代理问题总结前言 刚接触golang不久,有些环境无法融会贯通,现在针对开发过程中遇到的问题做个排查记录 问...
      99+
      2023-03-19
      golang 包无法引入 golang 包引入
    • IDEA中scala生成变量后自动显示变量类型问题怎么解决
      本篇内容主要讲解“IDEA中scala生成变量后自动显示变量类型问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“IDEA中scala生成变量后自动显示变量类型问题怎么解决”吧!idea...
      99+
      2023-07-06
    • numpy强制类型转换的问题怎么解决
      本篇内容主要讲解“numpy强制类型转换的问题怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“numpy强制类型转换的问题怎么解决”吧!numpy强制类型转换今天用numpy遇到一个关于类...
      99+
      2023-06-30
    • 泛型函数在Golang中解决可变参数类型的问题吗?
      go 中的泛型函数解决了可变参数类型的问题:泛型函数允许使用类型参数,在运行时指定。这使得编写可以处理不同类型参数的函数成为可能。例如,max 函数是一个泛型函数,它接受两个可比较参数并...
      99+
      2024-04-16
      golang 泛型
    • C++中常见的数据类型问题的解决方法
      C++中常见的数据类型问题的解决方法引言:在C++编程中,处理不同数据类型的问题是非常常见的。不同的数据类型具有不同的特征和用途,然而,在处理不同类型的数据时,我们经常会遇到一些问题。本文将介绍一些在处理C++中常见数据类型问题时的解决方法...
      99+
      2023-10-22
      数据类型 C++ 解决方法
    • java无法解析为类型怎么解决
      当遇到"Java无法解析为类型"的错误时,可能是由于以下几个原因造成的:1. 未正确导入Java类库:请确保导入了所需的Java类库...
      99+
      2023-08-28
      java
    • SAP MIGO可用数量无穷大问题怎么解决
      这篇文章主要讲解了“SAP MIGO可用数量无穷大问题怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SAP MIGO可用数量无穷大问题怎么解决”吧!本周收到业务的一个问题,MIGO投...
      99+
      2023-06-05
    • Node.js全局变量无法挂载问题怎么解决
      这篇文章主要介绍“Node.js全局变量无法挂载问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Node.js全局变量无法挂载问题怎么解决”文章能帮助大家解决问题。分析与解决 Node.j...
      99+
      2023-07-05
    • Golang共享变量如何解决问题
      目录1. 什么是竞态 2. 如何消除竞态 3. Go 提供的并发工具 3.1 互斥锁 3.2 读写互斥锁 3.3 Once 3.4 竞态检测器 4. 小结 在之前的文章中,我们详细说...
      99+
      2024-04-02
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作