什么是字面量
考虑下面代码:
Copy var a int = 50
var b string = "I love Go"
var c string = b
这里变量a
赋值为字面量50
,变量b
赋值为字面量I love Go
,而变量c
则赋值为变量b
。像5
, -89
,I love Go
,67.89
等,在编程语言中称为字面量。
什么是常量
常量是相对于变量而言的,考虑下面代码:
Copy var a int = 50
const b int = 50
这里两个量a
和b
虽然都是声明为int
类型,并且赋值为50,但是a
是变量,b
是常量。那么常量与变量有什么区别呢?答案是常量不可重新被赋值。
Copy package main
func main() {
const a = 55
a = 89 // 给常量重新赋值会报错
}
常量跟变量的另外一个不同点是,常量声明的同时需要赋值,因此下面的写法会报错:
Copy package main
func main() {
const int a // 先声明
a = 50 // 再赋值
}
另外需要注意,常量值需要在编译时确定,因此不能将函数调用的返回值赋值给常量。
Copy package main
import (
"fmt"
"math"
)
func main() {
fmt.Println("Hello, playground")
var a = math.Sqrt(4) // allowed
const b = math.Sqrt(4) // not allowed
}
该程序中,a
是变量,因此可以赋值为函数调用返回值;但是b
是常量,而函数math.Sqrt(4)
的执行是运行时,因此会报错。
无类型常量和有类型常量
Golang中每个变量都有对应的类型,比如:
Copy var a int = 10
var b = 20
c := 30
这三种不同的写法,声明的变量a
、b
、c
均为int
类型,虽然有显示声明的,有Golang自动推断的,有简写形式。
Golang中的常量与变量不同,常量包括两种:untyped常量(无类型常量)和typed常量(有类型常量)。为了方便理解,这里以香水为例来说明下。我们都知道,兰蔻(Lancome)和欧碧泉(Biotherm)都属于欧莱雅集团,假如他们公司新发明了一款香水:邂逅
。
Copy package main
import "fmt"
type Lancome string
type Biotherm string
func main() {
const perfume = "邂逅" // 无类型常量
const perfume1 Lancome = "邂逅" // 有类型常量,类型是兰蔻
const perfume2 Biotherm = "邂逅" // 有类型常量,类型是欧碧泉
var perfume3 Lancome = perfume // 合法
perfume3 = perfume1 // 合法
perfume3 = perfume2 // 不合法
fmt.Println(perfume, perfume1, perfume2, perfume3)
}
为了加深理解我们继续深挖香水这个例子。虽然邂逅
这款香水是欧莱雅集团出品的,但是在贴标之前是没有品牌属性的,即const perfume = "邂逅"
,这行代码我们 并未给perfume
常量贴标,因此不属于任何品牌,属于无类型常量。但是一旦贴标,比如const perfume2 Biotherm = "邂逅"
,这行代码我们给perfume2
常量贴标,贴上Biotherm品牌标志,即变为有类型常量。有类型常量是贴标产品,因此不能随便再撕下标签,贴上其他品牌的标志,比如perfume3 = perfume2
,因此这行代码是不合法的。
初看这个特性难以理解,但是这样使得Golang的常量更加灵活,我们首先声明无类型的常量,后面用起来就会更加灵活,只要类型兼容,想赋值给什么变量就赋值给什么变量。这里再解释下这里所说的类型兼容,比如const str = "邂逅"
中无类型常量str
本质是一个字符串,与类型string
、Lancome
均兼容,这里的类型兼容用来描述无类型常量与其他类型的兼容性:
Copy type Lancome string
const str = "邂逅"
var str1 string = str
var perfume1 Lancome = str
字符串常量
字符串常量声明如下:
Copy const hello = "Hello World"
参考前面对无类型常量和有类型常量的解释,这里声明了一个无类型字符串常量hello
。 看下下面的代码你可能会疑惑,为什么说hello
是无类型的呢,明明打印出了string
。
Copy package main
import (
"fmt"
)
func main() {
const name = "Sam"
fmt.Printf("type %T value %v", name, name)
}
运行结果如下:
Copy type string value Sam
这里解释下。前面之所以打印出了string
,并不是说常量name
是Golang的string
类型。本质原因是因为这里name
是作为了fmt.Printf
函数的参数,而该函数这里期望接收string
类型,又因为常量"Sam"本身是一个字符串,与string
类型兼容,因此才打印出了string
。
布尔常量
布尔常量没什么特殊的,很简答,这里仅举个例子:
Copy package main
func main() {
const trueConst = true
type myBool bool
var defaultBool = trueConst //allowed
var customBool myBool = trueConst //allowed
defaultBool = customBool //not allowed
}
数值常量
数值常量包括整型、浮点型以及复数型。
Copy package main
import (
"fmt"
)
func main() {
const a = 5
var intVar int = a
var int32Var int32 = a
var float64Var float64 = a
var complex64Var complex64 = a
fmt.Println("intVar",intVar, "\nint32Var", int32Var, "\nfloat64Var", float64Var, "\ncomplex64Var",complex64Var)
}
Copy intVar 5
int32Var 5
float64Var 5
complex64Var (5+0i)
从下面的程序我们可以看出整型变量、浮点型变量以及复数型变量被赋值常量时的默认类型分别是int
,float64
,complex128
:
Copy package main
import (
"fmt"
)
func main() {
var i = 5
var f = 5.6
var c = 5 + 6i
fmt.Printf("i's type %T, f's type %T, c's type %T", i, f, c)
}
Copy i's type int, f's type float64, c's type complex128
数值表达式
数值型常量声明时也不可以使用函数调用返回值来初始化,但是可以使用数值表达式来初始化,比如:
Copy package main
import (
"fmt"
)
func main() {
const a float64 = 5.9 / 5.9
fmt.Printf("a's type %T value %v", a, a)
}
执行结果如下:
Copy a's type float64 value 1