golang常量

148 阅读6分钟

常量

常量,定义的时候就需要指定值,且不能修改地址。

概述

常量使用关键字 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
	)