首页 > 编程笔记 > Go语言笔记 阅读:7

Go语言const常量的用法(非常详细)

常量是代码在编译阶段就确定下来的值,不能在运行时更改,如果尝试为常量分配新值,则会出现编译错误。

在 Go程序中,常量可以是数值类型(整型、浮点型和复数类型)、布尔类型和字符串类型等。

常量的表示方法有两种,即带类型的和不带类型的。常量相关的示例如下:
const i = 10
const f = 2.71828
 
const i int = 10
const f float64 = 2.71828
编译器可以对不带类型的常量做隐式类型转换。常量的精度要求是 256 位,也就是说,不带类型的常量最多可以用 256 比特来表示。字面量的值都属于不带类型的常量。

定义常量要使用关键字 const,其语法为:
const identifier [type] = value
不过,因为 Go语言编译器可以根据变量值推导类型,所以可以省略类型标识 type。

声明多个相同类型的常量时,该语法可以简写为:
const c_name1, c_name2 = value1, value2

GO 常量iota

Go 语言预定义了 true、false 和 iota 三个常量,其中 true 和 false 经常与布尔类型一起使用。

iota 是 Go语言中预定义的标识符,枚举常量时,它常用于自动生成连续值的序列。可以认为 iota 是一个自增枚举常量的计数器。

iota 只能在常量表达式中使用,常常被用于定义一组相关常量,它可以在不显式指定值的情况下自动递增。在每个关键字 const 出现时,iota 都会被重置为 0。在下个关键字 const 出现之前,每出现一次 iota,变量的值会在上个值的基础上增加 1。

下面的示例代码演示了通过 iota 定义一个星期中每一天的方式:
//枚举是一种特殊的数据类型,用于定义一组有限的、互不相同的值
//Go语言并不支持关键字enum,但可以使用关键字const创建一组相关的常量,这在概念上类似于枚举
//一组常量的定义方式通常是在关键字const后跟一对圆括号(常量就放在括号内)
//下面是常规的通过枚举的方式定义一个星期中每一天的示例
const (
        Monday = 1 + iota //1
        Tuesday             //2
        Wednesday           //3
        Thursday            //4
        Friday              //5
        Saturday            //6
        Sunday              //7
)
fmt.Println(Monday, Tuesday, Saturday) //输出: 1 2 6
在上述示例中,iota 的值会依次自动递增,此值从 0 开始,所以 Monday 的值是 1,Tuesday 的值是 2,以此类推。

在各种标准库中,为了方便开发人员使用,会预定义一些常量。例如,使用 log 包输出日志时,自带的 log 包默认的输入格式是内容和时间。

下面的示例提供了几个很简单的输出选项:
const (
        Ldate         = 1 << iota     //日期示例:2022/07/07
        Ltime                         //时间示例:01:23:45
        Lmicroseconds                 //微秒:01:23:45.000000.
        Llongfile                     //路径+文件名+行号:/a/b/c/d.go:10
        Lshortfile                    //文件名+行号:main.go:10
        LUTC                          //UTC时间格式
        LstdFlags     = Ldate | Ltime //默认
)
 
func init(){
   log.SetFlags(log.Ldate|log.Lshortfile)
}

Go语言常量的类型提升机制

在 Go语言中,变量的类型提升或者说隐式类型转换是不被直接支持的,这样的设计可以避免一些因隐式类型转换而导致的潜在问题。

不过,Go 语言中的常量有一些特殊的类型提升机制,未显式指定类型的常量被称为“无类型”常量,这样的常量在编译时会被隐式地转换为合适的类型。

例如,当无符号整数类型与有符号整数类型进行运算时,会自动将无符号整数类型提升为有符号整数类型,以避免可能出现的错误。另一个例子是当一个变量被赋值为一个常量时,如果常量被视为更高级别的数据类型,则变量的数据类型将自动提升为更高级别的。

需要注意的是,类型提升只会在特定的情况下发生,并不是所有情况下都会自动提升类型。因此,在编写代码时,仍然需要注意数据类型的匹配与转换。

下面这个示例演示了将 int 类型提升为 float 类型以及将不带类型的常量提升为带类型的常量的过程:
const int_n = 10
const float_e = 2.71828
 
var v = int_n*float_e
上述示例是基于 10 与 2.71828 做乘法运算。从字面上看,这是一个整数和一个浮点数相乘。

在 Go语言中,不支持让两个不同类型的变量之间发生隐式类型转换。但是常量相对特殊,编译器可以在变量和常量之间进行隐式类型转换。

在 Go语言中,字面量是不带类型的常量。由于常量 int_n 和 float_e 只有值,没有给出明确的类型,因此会根据类型提升机制,把常量 10 从整数常量提升为浮点数常量。这样一来,乘号两边就是相同类型的常量了。

接下来是一个有趣的内容,将 int_n*float_e 的值赋给变量v后,会降低结果的精度。这是因为常量的精度是 256 位,而变量 v 的精度只有 64 位,这样一来,结果的精度就从 256 位下降到了 64 位。

另外,常量与常量之间的运算也可能导致精度下降。示例代码如下:
const i int8 = 1
const j  = 2*i
常量 i 限制了类型为 int8,所以精度是 8 位。而常量 j 没有限制类型,所以精度是 256 位。但是将 i 的值赋给 j 后,根据类型提升机制,j 的精度就会从 256 位下降到 8 位。

需要注意的是,常量仅存在于编译期。下面这段代码在编译时不会报错:
const i = 123456789012345678901234567890 //编译时不会报错

相关文章