在go语言当中,不会改变的数据被称之为常量,通过关键字const
来声明。
常量通常是在编译阶段被创建的,即使在函数中定义的常量也是如此,同时常量的类型只能是布尔型、数字型(整数型、浮点型和复数)和字符串型。
由于编译时的限制,定义常量的表达式必须为能被编译器求值的常量表达式。
常量的声明
常量的定义语法格式如下:
const name type = value
例如,下面定义了一个常量:
const mysql_password string = "abc123"
当然,常量的定义也可以和变量一样,省略type
类型。编译器会如同编译变量那样来进行数据类型推断。
例如:
const mysql_user = "root"
如果需要声明一批常量,也可以采用类似于变量的方式进行声明。
const (
IP = "127.0.0.1"
pi = 3.1415926
)
如果在批量声明常量的时候,除了第一个常量的值必须设置以外,其他后面的常量值都可以省略,省略的常量值和第一个常量的值相同。
const (
a = 1
b
c
d
)
在上面的程序中,声明了四个常量,a、b、c、d,四个常量的值都等于1.
因为常量的值是在编译期间确定的,因此常量可以是构成类型的一部分,例如用于指定数组长度的类型:
const IPv4Len = 4
// parseIPv4 解析一个 IPv4 地址 (d.d.d.d).
func parseIPv4(s string) IP {
var p [IPv4Len]byte
// ...
}
常量生成器
常量声明可以使用 iota 常量生成器初始化,它用于生成一组以相似规则初始化的常量,但是不用每行都写一遍初始化表达式。在一个 const 声明语句中,在第一个声明的常量所在的行,iota 将会被置为 0,然后在每一个有常量声明的行加一。
例如下面的示例:
const (
a = iota
b
c
d
)
上面的四个常量的值都是通过iota
常量生成器进行的初始化,a的值为0,后面三个常量的值分别递增1.分别为1,2,3 。
无类型常量
在go语言当中,你既可以在声明常量的时候给常量指定类型,也可以不去指定类型。
在其中,编译器为没有明确基础数据类型的数字常量提供了比基础运算更高精度的算术运算,可以认为至少有256bit的运算精度。
无类型和有类型的数字常量
在 Go 语言中,你既可以在声明常量时指定类型,也可以不指定类型。当我们在代码中声明一个字面量时,我们其实就声明了一个匿名的、未指定类型的常量。
下面的例子展示了无类型的、有类型的命名常量和匿名常量:
const a = 12345
const b = 3.14159
const c int = 12345
const d float64 = 3.14159
声明的左边就是命名的常量,而右边的字面量其实是匿名的常量。
数字常量的种类
需要知道的是,变量的类型系统和常量的类型系统只是看上去一致,并不是相同的。常量如何表示与他们关联的值,有另外一套实现的方式。
当我们声明一个指定类型的常量的时候,声明时指定的类型是用来限定那个常量的精度的,它并不会改变常量的值在底层的数据结构,因为内部用什么数据结构来实现变量的值,不同的编译器有不同的实现方法。所以我们最好是认为,常量拥有的是种类(kind),而不是类型(type)
一个数字常量可以是以下种类之一:整数、浮点数、复数、Unicode 字符(rune):
12345 // kind: 整型
3.141592 // kind: 浮点数
1E6 // kind: 浮点数
在上面的示例中,我们声明了三个数字常量,一个是属于整数种类的,后两个是属于浮点种类的。字面量的形式就决定了它是什么种类的常量。当它的形式不包括小数点或者指数的时候,这个常量就是整数种类的。
常量完全精确的示例
我们可以声明一个超过int最大范围的值的常量,来说明常量的精度是非常大的。
package main
import "fmt"
// 远远大于 int64
const myConst = 9223372036854775808543522345
func main() {
fmt.Println("Will Compile")
}
上面的程序可以编译通过,原因在于整数种类的常量完全精确。
如果我们把上面的常量指定成 int64
类型的,那意思是这个常量的范围已经限定在 int64
的取值范围以内了,这个时候程序不会编译成功:
package main
import "fmt"
// Much larger value than int64.
const myConst int64 = 9223372036854775808543522345
func main() {
fmt.Println("Will NOT Compile")
}
Compiler Error:
./ideal.go:6: constant 9223372036854775808543522345 overflows int64
从上面我们可以知道,整数种类的常量可以表示非常大的数字。并且能够理解为什么我们说,常量是完全精确的。
数字常量的声明
当我们声明一个无类型的常量的时候,Go对这个常量的值没有任何的要求:
const a = 12345 // 种类:整数
const b = 3.14159 // 种类:浮点数
上面的示例中,左边的常量被赋予与右边的常量相同的值和种类。
当我们声明一个有类型的常量的时候,右边的常量的形式必须要与声明的左边的常量的类型兼容:
const a int = 12345 // 种类:整数
const b float64 = 3.141592 // 种类:浮点数
声明的右边的值也必须在声明的类型的有效范围内。比如说,下面的数字常量的声明是无效的:
const myUint8 uint8 = 1000
uint8
只能表示0-255的数字范围,这也是上面我们说,指定的类型就是用来限定常量精度的。
隐式的整形转换
在 Go 的世界中,变量都不会发生隐式的转换。然而,常量与变量之间的隐式类型转换则经常发生。
我们先来看看隐式的整形转换:
var myInt int = 123
这个示例中,我们有一个整数种类的常量 123
,它被隐式地转换成 int
类型。因为这个常量的字面值中没有小数点或者指数,这个常量将会作为一个整数种类的常量。整数种类的常量可以隐式地转换成有符号或者无符号的、任意长度的变量,只要整个过程没有发生数据的溢出。
浮点数的种类的常量也可以隐式地转换成整型变量,只要这个常量的值的形式是可以兼容整型的:
var myInt int = 123.0
我们还可以进行隐式的常量 - 变量转换时,省略变量的类型指定:
var myInt = 123
在这个例子中,当我们用值为 123
的整数常量来初始化 myInt
变量时,myInt
会隐式地采用默认的 int64
类型。
隐式的浮点类型转换
我们接着来看看隐式的浮点型转换:
var myFloat float64 = 0.333
这时候编译器会执行一个隐式转换,从浮点数种类的常量 0.333
转换为 float64
类型的浮点型变量。因为常量字面值中含有一个小数点,所以这个常量是一个浮点数种类的常量。默认情况下,会把一个浮点数种类的常量转换为 float64
类型的变量。
编译器还可以把整数类型的常量隐式的转换成为 float64
类型的变量。
var myFloat float64 = 1
在这个示例中,整数常量 1
被隐式地转换成 float64
类型的变量了。