常量
-
常量是在程序运行过程中,其值不可以发生改变的数据
,常量无法被获取地址 -
常量中的数据类型能是布尔型、数字型(整型、浮点型和复数型)、字符串
-
常量的定义是通过
const
关键字完成的,并且常量名称大写为公开,小写为私有,一般定义在函数外,定义在函数内属于局部常量 -
常量和变量一样,可以省略数据类型,由编译器推断完成
常量的定义
const Name string = "不知火舞"
const Age = 99
const Address = "峡谷76号"
const name, age, address = "李白", 99, "峡谷野区草丛"// 当常量比较多的时候可以使用常量块来表示,比较简洁
const (USERNAME = "干将莫邪"AGE = 88ADDRESS = "中路草丛"
)// 也可以批量赋值
const GENDER, HOBBY = "男", "黑丝"
常量除不可以再次赋值外,和变量究竟有什么不同?
-
常量不会分配存储空间,无需像变量那样通过内存寻址来取值,因此无法获取地址。
-
常量值不能再次改变,变量可以
const NAME = "itzhuzhu"func main() {NAME = "haha" // 报错
}
函数内外都有相同常量时采用就近原则
const (USERNAME = "干将莫邪"AGE = 88ADDRESS = "中路草丛"
)func main() {const USERNAME, AGE, ADDRESS = "itzhuzhu", 24, "中国"fmt.Println(USERNAME, AGE, ADDRESS) // 就近原则打印的是itzhuzhu
}
定义常量不使用不会编译错误,不同作用域也可以定义相同常量
func main() {const X = 123fmt.Println("我是外面的:", X)const Y = 1.23 // 未使用不会引发编译错误{const X = 321 // 不同作用域定义同名常量fmt.Println("我是里面的:", X)}
}
常量值也可以是某些编译器能直接计算结果的表达式,如unsafe.Sizeof、len、cap等
func main() {const (ptrSize = unsafe.Sizeof(uintptr(0)) // 函数返回操作数在内存中的字节大小strSize = len("hello, world!"))fmt.Println(ptrSize)fmt.Println(strSize)
}
在常量组中如不指定类型和初始化值,则与上一行非空常量的值相同
func main() {const (X uint16 = 120Y // 与上一行x类型、右值相同S = "abc"Z // 与s类型、右值相同)fmt.Printf("%T, %v\n", Y, Y) // 输出类型和值fmt.Printf("%T, %v\n", Z, Z)
}
打印结果
uint16, 120
string, abc
显示常量和隐式定义常量区别,这里没搞懂原因,x默认是int类型,int转给byte,也没有做强转
func main() {const x = 100 // 隐式无常量类型,值随便写const y byte = x // 相当于const y byte = 100const a int = 100 // 显式指定常量类型,编译器会做强类型検查const b byte = a // 错误:无法将 'a' (类型 int) 用作类型 byt
}
那为什么隐式的可以赋值,显示的不能赋值呢?
iota:
枚举就是将数据值一一列出来,枚举可以用来表示一些固定的值,枚举是常量组成的。在Go可以通过iota实现枚举的功能。
iota是Go语言的常量计数器,const出现时,会将iota初始化为0,const中每新增一行iota就会计数一次,递增默认数据类型为int
iota可以持续递增
const (a = 1b = 2c = 3)
上面代码使用iota可以简化为
const (a = iota // 第一行 重置为0 a:0b // 第二行 新增1行 b:1c // 第三行 新增1行 c:2)
自增默认类型为int,不过可显式指定常量类型
const (a = iota // int iota = 0b float32 = iota // float32 iota = 1c // float32 iota = 2)fmt.Println(a, b, c)fmt.Printf("%T\n%T\n%T\n", a, b, c)
_
跳过值
const (a = iota // 0_ // 1c // 2d // 3)fmt.Println(a, c, d)
使用位移计算
const (_ = iota // 0KB = 1 << (10 * iota) // 1 << (10 * 1)MB // 1 << (10 * 2)GB // 1 << (10 * 3))
如果中断iota递增,必须再次遇到iota才会恢复按行递增,否则将沿用上一次取值
const (a = 1 + iota // 第0行 重置为0 a = 1 + 0b // 第1行 新增1行 b = 1 + 1c // 第2行 新增1行 c = 1 + 2d = 4 // 第3行 新增1行 d = 4e // 第4行 新增1行 e = 4 与上一行常量右值表达式相同f // 第5行 新增1行 f = 4 只要不遇到iota,就一直是上次赋值的值,就是4g = iota // 第6行 重置为0 g = 6 这里遇到了iota,恢复iota自增,计数包括前面所有的常量i // 第7行 新增1行 i = 7 接着g+1,如果再定义常量初始化,就还是和4一样循环j // 第8行 新增1行 i = 8
)func main() {fmt.Println(a, b, c, d, e, f, g, i, j)
}
如果使用多个常量赋值的时候,后面的数据都会跟着第一行的格式走,直到下一个iota出现
const (a, b = 1 + iota, 2 + iota // iota = 0 a = iota + 1 b = iota + 2 a = 1 ,b = 2c, d // iota = 1 c = iota + 1 d = iota + 2 c = 2 ,d = 3e, f // iota = 2 e = iota + 1 f = iota + 2 e = 3 ,f = 4g, h = 3 + iota, 4 + iota // iota = 3 g = iota + 3 h = iota + 4 g = 6 ,h = 7i, j // iota = 4 i = iota + 3 j = iota + 4 i = 7 ,j = 8
)
fmt.Println(a, b, c, d, e, f, g, h, i, j)
可以自定义类型来实现用途明确的枚举类型。但须注意,这并不能将取值限定在预定义的枚举常量值范围内。
func main() {test(red)test(10000000) // 错误:10000000超出color/byte类型取值范围。x := 2test(x) // 错误:无法将 'x' (类型 int) 用作类型 color
}type color byte // 自定义类型const (black color = iota // 指定常量类型redblue
)func test(c color) {fmt.Println(c)
}