看完了变量的定义,再来看常量。
GO语言中常量定义使用关键字const,这个关键字倒是和C++相像。
常量的定义方法和变量定义差不多,这里就一笔带过了。
const a int = 5
func main() {
const b int = 5
fmt.Println(a,b)
}
const (
a int = 5
b int = 5
)
func main() {
fmt.Println(a,b)
}
func main() {
const a,b int = 5,5
fmt.Println(a,b)
}
func main() {
const a,b = 5,5
fmt.Println(a,b)
fmt.Println(reflect.TypeOf(a),reflect.TypeOf(b))
}
//输出结果
5 5
int int
可以看到常量的定义和变量是差不多的,只不过有几个地方需要注意
func main() {
a,b := 5,5
fmt.Println(a,b)
}
//上面这就是变量的定义了,不是常量
func main() {
const a int
fmt.Println(a)
}
//错误提示
.\main.go:9:10: missing value in const declaration
func main() {
const a,b := 5,5
fmt.Println(a,b)
}
//错误提示
.\main.go:9:8: missing value in const declaration
.\main.go:9:12: syntax error: unexpected := at end of statement
另外,还有一个点需要注意,这个是编译器方面的推断类型导致的,看如下代码
func main() {
a,b := 3,4
var c int
c = int (math.Sqrt(a*a + b*b))
fmt.Println(c)
}
程序会报错,因为sqrt函数的参数浮点类型,而这里a和b是变量,编译器将a和b推断成了int类型,要变成浮点类型必须强转
.\main.go:12:25: cannot use a * a + b * b (type int) as type float64 in argument to math.Sqrt
但是如果a和b是常量,就可以了
func main() {
const a,b = 3,4
var c int
c = int (math.Sqrt(a*a + b*b))
fmt.Println(c)
}
//输出结果
5
这是因为,常量其实本质上做的是一个文本替换,这里的a和b它既可以是int,也可以是浮点型,编译器不管这个,编译器只将a和b出现的地方用3和4代替了,实际上,那句sqrt相当于下面的表达式
c = int (math.Sqrt(25))
这是常量和变量在省略类型时的一点参数,只要注意常量的话它会是一个文本替换,可以作为任意类型使用,而变量是推断出具体类型。
还可以使用一些内置表达式来定义常量,如:len(),unsafe.Sizeof()等
const name = "pigff"
const length = len(name)
const size = unsafe.Sizeof(name) //用于求变量大小
func main() {
fmt.Println(name,length,size)
}
输出结果
pigff 5 16
注意看,这里为什么Sizeof一个字符串的大小会是16?原因是GO中的sring内部实现由两部分组成,一部分是指向字符串起始地址的指针,另一部分是字符串的长度,两部分各是8字节,所以一共16字节。这部分具体会在后面的文章说到,这里提一下。
和C++做个对比,len其实相当于C++中string类的length接口,而C++中对于字符串求sizeof的大小是根据编译器决定的,不同平台下求出的结果也不一样,vs2017下求出来时28,而Linux下用g++求出来就是8,具体要看平台,编译器,以及编译器版本。
自己实现的函数,不可以这样用来赋值给常量
func fun(name string) string{
return name
}
const name = fun("pigff")
func main() {
fmt.Println(name)
}
程序会报错
.\main.go:11:7: const initializer fun("pigff") is not a constant
所以只有内置的表达式和函数才可以这么定义。
GO语言中有一个特殊常量——枚举类型,C++中有enum关键字来定义枚举类型,而GO语言中则没有这样的关键字,GO中使用一组const常量来表示枚举类型。
我们知道,枚举类型的数值是从0开始的,为了对比,我们先来看一下一段C++代码。
#include
using namespace std;
enum{
EAST,
SOUTH,
WEST,
NORTH
};
int main(){
int a[] = {EAST,SOUTH,WEST,NORTH};
for(int i = 0; i < 4; ++i)
cout << a[i] << " ";
cout << endl;
return 0;
}
我们在main函数中对这几个枚举值一一输出它们的值,结果如下
0 1 2 3
可以看到确实是从0开始的,那么这样的枚举类型在GO语言中是如何实现的呢?
GO使用一组const来表示枚举类型,并使用了iota这个常量计数器
先试着像C++那样定义枚举类型
const (
EAST
SOUTH
WEST
NORTH
)
func main() {
fmt.Println(EAST,SOUTH,WEST,NORTH)
}
诚然,因为这些常量没有定义,编译器会报错
.\main.go:6:2: missing value in const declaration
那么我们就可以给它们来手动定义
const (
EAST = 0
SOUTH = 1
WEST = 2
NORTH = 3
)
func main() {
fmt.Println(EAST,SOUTH,WEST,NORTH)
}
输出的结果就是预期的
0 1 2 3
那么如果这个我们想要表达的枚举类型很多怎么办?我们都手动定义吗,不能像C++那样从0开始自动增长吗?
为了解决这个问题,引入了常量计数器iota,来看下GO语言是怎么做到自动增长的
const (
EAST = iota
SOUTH
WEST
NORTH
)
func main() {
fmt.Println(EAST,SOUTH,WEST,NORTH)
}
输出结果和上面一样
0 1 2 3
好了,下面来具体了解一下这个iota到底是个啥
iota是GO语言的常量计数器,只可以在常量表达式中使用(给常量赋值)
上面就是使用iota这个常量计数器的关键。
func main() {
fmt.Println(iota)
}
程序会报错,以为iota是一个变量名
.\main.go:13:14: undefined: iota
func main() {
const (
a = iota //iota为0,a为0
b //新增了一行常量定义,iota++,b为1
c //新增了一行常量定义,iota++,c为2
)
fmt.Println(a,b,c)
}
输出结果如下
0 1 2
func main() {
const (
a = iota
b
c
)
const (
d = iota
e
f
)
fmt.Println(a,b,c)
fmt.Println(d,e,f)
}
输出结果如下
0 1 2
0 1 2
iota有多种使用方法,一起来看一下
func main() {
const (
a = iota //a是0
b //b是1
_ //2被跳过了
c //c是3
)
fmt.Println(a,b,c)
}
输出结果
0 1 3
在a和c之间插入一个不是iota赋值的常量b,这个时候iota还是会+1
func main() {
const (
a = iota //a是0
b = 3 //b是3,iota仍旧++
c = iota //c是2,不是0,此时iota是2
)
fmt.Println(a,b,c)
}
输出结果
0 3 2
如果后面的常量没有赋值,那么会向上找第一个不为空的赋值表达式
func main() {
const (
a = iota * 2 //a是0,iota++
b = iota //b是1,iota++
c = iota //c是2
)
fmt.Println(a,b,c)
}
这个时候,把b和c的赋值都省略
func main() {
const (
a = iota * 2 //a是0,iota++
b //b是2,iota++
c //c是4
)
fmt.Println(a,b,c)
}
输出结果如下
0 2 4
验证一下,会向上使用第一个非空的赋值表达式
func main() {
const (
a = iota * 2 //a是0,iota++
b = iota * 3 //b是3,iota++
c //c是6,沿用了b的赋值表达式,而不是a的
d //d是9,沿用了b的赋值表达式,而不是a的
)
fmt.Println(a,b,c,d)
}
输出结果如下
0 3 6 9
因此,通过这种方法,可以有多元化的常量赋值,不一定是自增长的,也可以是二倍自增的,这也是GO语言枚举类型的一个巧妙之处
格式一致,沿用之前对应的赋值格式
func main() {
const (
a,b = iota,iota + 2 //a为0,b为2,iota++
c,d //等价于c = iota,d = iota + 2,所以c为1,b为3
)
fmt.Println(a,b,c,d)
}
输出结果
0 2 1 3
注意格式必须一致,格式不一致就会导致出错的问题(即第一行是两个变量,后面的也必须是两个变量)
func main() {
const (
a,b = iota,iota + 2
c,d
e //格式不一致
)
fmt.Println(a,b,c,d)
}
上面程序格式不一致会出错
.\main.go:16:3: extra expression in const declaration