常量
常量,定义的时候就需要指定值,且不能修改地址。
概述
常量使用关键字 const 定义,用于存储不会改变的数据。
存储在常量中的数据类型只可以是布尔型、数字型(整数型、浮点型、复数)和字符串型。
定义格式
const identifier [type] = value
类型定义
在 Go 语言中,你可以省略类型说明符 [type],因为编译器可以根据常量的值来推断其类型。
//显式类型定义
const b string = "abc"
//隐式类型定义
const b = "abc"
一个没有指定类型的常量被使用时,会根据其使用环境而推断出它所需要具备的类型。换句话说,未定义类型的常量会在必要时刻根据上下文来获得相关类型。
赋值性质
常量的值必须是在编译时就能够确定的;你可以在其赋值表达式中涉及计算过程,但是所有用于计算的值必须在编译期间就能获得。
func getNumber() int{
return 5
}
//正确的做法
const c1 = 2/3
//错误的做法
// 引发构建错误: getNumber() used as value
const c2 = getNumber()
因为在编译期间自定义函数均属于未知,因此无法用于常量的赋值,但内置函数可以使用,如:len ()。
数字赋值
数字型的常量是没有大小和符号的,并且可以使用任何精度而不会导致溢出。
const Ln2= 0.693147180559945309417232121458\
176568075500134360255254120680009
// this is a precise reciprocal
const Log2E= 1/Ln2
// float constant
const Billion = 1e9
const hardEight = (1 << 100) >> 97
根据上面的例子我们可以看到,反斜杠 \ 可以在常量表达式中作为多行的连接符使用。(此处的反斜杠已经不能作为多行的连接符使用了).
与各种类型的数字型变量相比,你无需担心常量之间的类型转换问题,因为它们都是非常理想的数字。
不过需要注意的是,当常量赋值给一个精度过小的数字型变量时,可能会因为无法正确表达常量所代表的数值而导致溢出,这会在编译期间就引发错误。
常量的定义
1.基本语法
const 常量名 类型 = 常量值
举例:
package main
func main() {
//常量,定义的时候就指定的值,不能修改
/*
①显式定义指明类型
const 常量名 类型 = 常量值
*/
const PI float32= 3.1415
}
2.不显示指明类型,使用自动推导
const 常量名 = 常量值
举例:
package main
func main() {
/*
②隐式定义(不指名类型由值的类型推断)
const 常量名 = 常量值
*/
const MY_INFO = "小白"
}
3.连续定义多个同类型的变量
const 常量A,常量B 类型 = 常量值A,常量值B
举例:
package main
func main() {
const c,d int = 25,30
}
4.定义多个不同类型的常量,使用类型推导
const 常量A,常量B = 常量值A,常量值B
举例:
package main
func main() {
const e,f = 25,"hello"
}
5.抽离const,
这在项目中很常用,多用于定义全局常量
const (
常量名 类型 = 常量值
常量名 = 常量值
)
举例:
package main
func main() {
/*
③定义多个常量,相当于抽离const
*/
const (
UNKNOWN int = 1
FEMALE = 2
MALE = 3
)
}
6.组合定义
仅用于抽离const的情形,具有以下特性
1.如果没有给定值和类型将沿用上面最近的一个值和类型
2.所以第一个必须有值
举例:
package main
func main() {
/*
④组合定义
组合定义的规则:
1.如果没有给定值和类型将沿用上面最近的一个值和类型
2.所以第一个必须有值
*/
const (
// 第一个必须有值
// P
X int = 16
//沿用 X,相当于 const Y int = 16
Y
S = "abc"
//沿用S,相当于 const Z="abc"
Z
//沿用S,相当于 const M="abc"
M
)
}
7.小结
规范:
①常量全部大写 PI
②多个单词之间采用下划线分隔 MY_INFO
规则:
①常量类型只可以定义bool、数字(整数、浮点数、复数)和字符串
②不曾使用的常量不报错,不强制使用
③显式指定类型的时候,必须保证等号左右类型一致
④常量必须赋初始值
举例:
package main
func main() {
/*
常量必须赋初始值,只声明不赋值会报错
*/
// const XI string
}
iota常量
package main
import "fmt"
func main() {
/*
①iota 特殊常量
可以认为是一个能被编译器修改的常量
在编译的时候根据iota自动推断值
*/
const (
ERROR = iota
SUCCESS = iota
WIN = iota
FAIL = iota
)
fmt.Println(ERROR,SUCCESS,WIN,FAIL) //0 1 2 3
fmt.Println(WIN,FAIL,ERROR,SUCCESS) //2 3 0 1
//可以发现在编译时他自动推断了值,与执行顺序无关
/*
②iota内部有一个计数器,默认从0开始
按照组合式定义进行优化
由于沿用之前的值和类型,那么AGE2与AGE3的值都会是iota
根据iota计数器自增,最终得到
AGE2 = 1
AGE3 = 2
注意:继承的值是iota,而不是iota计算后的值
例如值是iota+5 ,那么继承得到的值就是 iota+5
*/
const (
AGE1 = iota
AGE2
AGE3
)
/*
③由于iota初始是0,那么我们可以修改初始值来改变起点
*/
const (
ERR6 = iota+2 //2
ERR9 //3
ERR4 //4
)
/*
④ iota计数器不会中断
1.每一次值都会被记录,C为字符串,但是iota计数器仍然执行了
2.如果中断了iota,后续还要用他必须显式的恢复
理解:如果你不恢复他,后续的就继承不了他,虽然他计数器没断,但是没有值用他
*/
const (
A = iota //0
B //1
C = "haha" //haha
D //haha
E //haha
F = iota //5
G //6
H = iota+5 // 7+5 = 12
I //iota+5 = 8+5 =13
)
fmt.Println(A,B,C,D,E,F,G,H,I) //0 1 haha haha haha 5 6 12 13
/*
⑤每次出现const关键字的时候 iota归零
*/
const ABC = iota //0
const (
BCD = iota //0
GDP //1
)
const TNT = iota //0
}
注意事项
1.iota是个特殊常量,继承时继承的是iota而不是iota计算后的值
const (
ERR6 = iota+2 //0+2 = 2
ERR9 //iota+2 = 1+2 = 3
ERR4 //iota+2 = 2+2 =4
)
2.计算器不会被打断,iota从0开始
const (
A = iota+1 // 0+1 = 1 iota为0
B // iota+1 = 1+1 =2 iota为1
C = "haha" //haha iota为2
D //haha iota为3
E //haha iota为4
F = iota //5 iota为5
G //6 iota为6
H = iota+5 // 7+5 = 12 iota为7
I //iota+5 = 8+5 =13 iota为8
)