Go_常量、iota(枚举)的使用

常量

  • 常量是在程序运行过程中,其值不可以发生改变的数据,常量无法被获取地址

  • 常量中的数据类型能是布尔型、数字型(整型、浮点型和复数型)、字符串

  • 常量的定义是通过const关键字完成的,并且常量名称大写为公开,小写为私有,一般定义在函数外,定义在函数内属于局部常量

  • 常量和变量一样,可以省略数据类型,由编译器推断完成

常量的定义

const Name string = "不知火舞"
const Age = 99
const Address = "峡谷76号"

// 当常量比较多的时候可以使用常量块来表示,比较简洁
const (
	USERNAME = "干将莫邪"
	AGE      = 88
	ADDRESS  = "中路草丛"
)

// 也可以批量赋值
const name, age, address = "李白", 99, "峡谷野区草丛"

常量除不可以再次赋值外,和变量究竟有什么不同?

  • 常量不会分配存储空间,无需像变量那样通过内存地址取值,因此无法获取内存地址。

  • 常量值不能修改,变量可以

const NAME = "itzhuzhu"

func main() {
	NAME = "haha" // 报错,不能修改
}

函数内外都有相同常量时采用就近原则

const (
	USERNAME = "干将莫邪"
	AGE      = 88
	ADDRESS  = "中路草丛"
)

func main() {
	const USERNAME, AGE, ADDRESS = "itzhuzhu", 24, "中国"
	fmt.Println(USERNAME, AGE, ADDRESS) // 就近原则打印的是itzhuzhu
}

定义常量不使用不会报编译错误,不同作用域也可以定义相同常量

func main() {
	const X = 123
	fmt.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 = 120
		Y        // 与上一行x类型、右值相同
		W = "abc"
		Z        // 与s类型、右值相同
	)
	fmt.Printf("%T, %v\n", Y, Y) // 输出类型和值
	fmt.Printf("%T, %v\n", Z, Z)
}

打印结果

uint16, 120
string, abc

显示常量和隐式定义常量区别,这里没搞懂为什么隐式不会做强类型检查

func main() {
	const x = 100     // 隐式无常量类型,值随便写
	const y byte = x  // 相当于const y byte = 100

	const a int = 100 // 显式指定常量类型,编译器会做强类型検查
	const b byte = a  // 错误:无法将 'a' (类型 int) 用作类型 byt
  const b byte = byte(a) // 只能通过强转
}

iota:

枚举就是将数据值一一列出来,枚举可以用来表示一些固定的值,枚举是常量组成的。在Go可以通过iota实现枚举的功能。

iota是Go语言的常量计数器,const出现时,会将iota初始化为0,const中每新增一行iota就会计数一次,递增默认数据类型为int

iota可以持续递增

	const (
		a = 1
		b = 2
		c = 3
	)

上面代码使用iota可以简化为

	const (
		a = iota // 第一行	重置为0	a:0
		b        // 第二行	新增1行	b:1
		c        // 第三行	新增1行	c:2
	)

自增默认类型为int,不过可显式指定常量类型

	const (
		a         = iota // int        iota = 0
		b float32 = iota // float32    iota = 1
		c                // float32    iota = 2
	)
	fmt.Println(a, b, c)
	fmt.Printf("%T\n%T\n%T\n", a, b, c)

_跳过当前常量值

	const (
		a = iota  // 0
		_         // 1
		c         // 2
		d         // 3
	)
	fmt.Println(a, c, d)

使用位移计算

	const (
		_  = iota             // 0
		KB = 1 << (10 * iota) // 1 << (10 * 1)
		MB                    // 1 << (10 * 2)
		GB                    // 1 << (10 * 3)
	)

如果中断iota递增,必须再次遇到iota才会恢复按行递增,否则将沿用上一次取值

const (
	a = 1 + iota // 第0行	重置为0	a = 1 + 0
	b            // 第1行	新增1行	b = 1 + 1
	c            // 第2行	新增1行	c = 1 + 2
	d = 4        // 第3行	新增1行	d = 4
	e            // 第4行	新增1行	e = 4   与上一行常量右值表达式相同
	f            // 第5行	新增1行	f = 4   只要不遇到iota,就一直是上次赋值的值,就是4
	g = 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 = 2
		c, d                      // iota = 1	c = iota + 1	d = iota + 2	c = 2 ,d = 3
		e, f                      // iota = 2	e = iota + 1	f = iota + 2	e = 3 ,f = 4
		g, h = 3 + iota, 4 + iota // iota = 3	g = iota + 3	h = iota + 4	g = 6 ,h = 7
		i, 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 := 2
	test(x) // 错误:无法将 'x' (类型 int) 用作类型 color
}

type color byte // 自定义类型

const (
	black color = iota // 指定常量类型
	red
	blue
)

func test(c color) {
	fmt.Println(c)
}

你可能感兴趣的:(Golang,golang,枚举,iota)