定义
关键字 const
被用于表示常量,常量用于存储不会改变的数据,常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
const identifier [type] = value
常量不能再重新赋值为其他的值
const a = 55 // 允许
a = 89 // 不允许重新赋值
常量的值会在编译的时候确定。因为函数调用发生在运行时,所以不能将函数的返回值赋值给常量。
package main
import (
"fmt"
"math"
)
func main() {
fmt.Println("Hello, playground")
var a = math.Sqrt(4) // 允许
const b = math.Sqrt(4) // 不允许
}
在上面的程序中,因为 a
是变量,因此我们可以将函数 math.Sqrt(4)
的返回值赋值给它(我们将在单独的地方详细讨论函数)。
b
是一个常量,它的值需要在编译的时候就确定。函数 math.Sqrt(4)
只会在运行的时候计算,因此 const b = math.Sqrt(4)
将会抛出错误 error main.go:11: const initializer math.Sqrt(4) is not a constant)
字符串常量
双引号中的任何值都是 Go 中的字符串常量。例如像 Hello World
或 Sam
等字符串在 Go 中都是常量。
什么类型的字符串属于常量?答案是他们是无类型的。
像 Hello World
这样的字符串常量没有任何类型。
const hello = "Hello World"
上面的例子,我们把 Hello World
分配给常量 hello
。现在常量 hello
有类型吗?答案是没有。常量仍然没有类型。Go 是一门强类型语言,所有的变量必须有明确的类型。那么, 下面的程序是如何将无类型的常量 Sam
赋值给变量 name
的呢?
package main
import (
"fmt"
)
func main() {
var name = "Sam"
fmt.Printf("type %T value %v", name, name)
}
答案是无类型的常量有一个与它们相关联的默认类型,并且当且仅当一行代码需要时才提供它。在声明中 var name = "Sam"
, name
需要一个类型,它从字符串常量 Sam
的默认类型中获取。**
有没有办法创建一个带类型的常量?答案是可以的。以下代码创建一个有类型常量。
const typedhello string = "Hello World"
上面代码中, typedhello
就是一个 string
类型的常量。
Go 是一个强类型的语言,在分配过程中混合类型是不允许的。让我们通过以下程序看看这句话是什么意思。
package main
func main() {
var defaultName = "Sam" // 允许
type myString string
var customName myString = "Sam" // 允许
customName = defaultName // 不允许
}
在上面的代码中,我们首先创建一个变量 defaultName
并分配一个常量 Sam
。常量 Sam
的默认类型是 string
,所以在赋值后defaultName
是 string
类型的。
下一行,我们将创建一个新类型 myString
,它是 string
的别名。
然后我们创建一个 myString
的变量 customName
并且给他赋值一个常量 Sam
。因为常量 Sam
是无类型的,它可以分配给任何字符串变量。因此这个赋值是允许的,customName
的类型是 myString
。
现在,我们有一个类型为 string
的变量 defaultName
和另一个类型为 myString
的变量 customName
。即使我们知道这个 myString
是 string
类型的别名。Go 的类型策略不允许将一种类型的变量赋值给另一种类型的变量。因此将 defaultName
赋值给 customName
是不允许的,编译器会抛出一个错误 main.go:7:20: cannot use defaultName (type string) as type myString in assignmen
。
布尔常量
布尔常量和字符串常量没有什么不同。他们是两个无类型的常量 true
和 false
。字符串常量的规则适用于布尔常量,所以在这里我们不再重复。以下是解释布尔常量的简单程序。
package main
func main() {
const trueConst = true
type myBool bool
var defaultBool = trueConst // 允许
var customBool myBool = trueConst // 允许
defaultBool = customBool // 不允许
}
上面的程序是自我解释的。
数字常量
数字常量包含整数、浮点数和复数的常量。数字常量中有一些微妙之处。
让我们看一些例子来说清楚。
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)
}
上面的程序,常量 a
是没有类型的,它的值是 5
。您可能想知道 a
的默认类型是什么,如果它确实有一个的话, 那么我们如何将它分配给不同类型的变量。答案在于 a
的语法。下面的程序将使事情更加清晰。
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)
}
在上面的程序中,每个变量的类型由数字常量的语法决定。5
在语法中是整数, 5.6
是浮点数,5+6i
的语法是复数。当我们运行上面的程序,它会打印出 i's type int, f's type float64, c's type complex128
。
现在我希望下面的程序能够正确的工作。
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)
}
在这个程序中, a
的值是 5
,a
的语法是通用的(它可以代表一个浮点数、整数甚至是一个没有虚部的复数),因此可以将其分配给任何兼容的类型。这些常量的默认类型可以被认为是根据上下文在运行中生成的。 var intVar int = a
要求 a
是 int
,所以它变成一个 int
常量。 var complex64Var complex64 = a
要求 a
是 complex64
,因此它变成一个复数类型。很简单的:)。
枚举
常量还可以用作枚举, 如下数字 0、1 和 2 分别代表未知性别、女性和男性
const (
Unknown = 0
Female = 1
Male = 2
)
关键字iota,这个关键字用来声明enum的时候采用,它默认开始值是0,const中每增加一行加1:
const (
x = iota // x == 0
y // y == 1
z // z == 2
w //w ==3
)
func main() {
fmt.Println(x,y,z,w)
}
位运算方式
const (
Open = 1 << iota //1
Close //2
Pending //4
)