NotePublic/Software/Development/Language/Go/Basic/Golang_中的常量.md

7.3 KiB
Raw Blame History

Golang 中的常量

1. 常量定义及分类

1.1. 定义

常量是指在程序运行时,不会被修改的量。

常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。

常量的定义格式:

const identifier [type] = value

可以省略类型说明符 [type],因为编译器可以根据变量的值来推断其类型。

  • 显式类型定义

    const b string = "abc"
    
  • 隐式类型定义

    const b = "abc"
    

多个相同类型的声明可以简写为:

const name1, name2 = value1, value2

1.2. 分类

flowchart LR
const(常量)
int(整形常量)
plural(复数常量)
char(字符常量)
float(浮点常量)
string(字符串常量)

int_ins0(21)
int_ins1(0xAbcdef)
plural_ins0(0.25i)
plural_ins1(1.e+4i)
char_ins0('a')
char_ins1('\t')
char_ins2('中')
float_ins0(0.2)
float_ins1(1.e+0)
float_ins2(1E4)
string_ins0(''hello world'')
string_ins1(''程序员'')

const---int
int---int_ins0
int---int_ins1

const---plural
plural---plural_ins0
plural---plural_ins1

const---char
char---char_ins0
char---char_ins1
char---char_ins2

const---float
float---float_ins0
float---float_ins1
float---float_ins2

const---string
string---string_ins0
string---string_ins1
  • 字符常量Go 的源码采用的是 UTF-8 的编码方式UTF-8 的字符占用的字节数可以有 14 个字节Rune 字符常量也有多种表现形式,但是使用''(单引号)将其括住。
  • 字符串常量:字符串常量基本表现形式就是使用""(双引号)将字符序列包括在内,双引号里面可以是 UTF-8 的字符字面量,也可以是其编码值。

2. 常量使用

package main

import "fmt"

func main() {
   const LENGTH int = 10
   const WIDTH int = 5   
   var area int
   const a, b, c = 1, false, "str" //多重赋值

   area = LENGTH * WIDTH
   fmt.Printf("面积为 : %d", area)
   println()
   println(a, b, c)   
}

// 输出结果为:
// 面积为 : 50
// 1 false str

3. 常量作为枚举

const (
    Unknown = 0
    Female = 1
    Male = 2
)

数字 0、1 和 2 分别代表未知性别、女性和男性。

常量可以用 len(), cap(), unsafe.Sizeof() 函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过:

在包一级声明语句声明的名字可在整个包对应的每个源文件中访问,而不是仅仅在其声明语句所在的源文件中访问。如下代码中的 a 、b 、c 。

package main

import "unsafe"
const (
    a = "abc"
    b = len(a)
    c = unsafe.Sizeof(a)
)

func main(){
    println(a, b, c)
}

// 运行结果为:
// abc 3 16

注意:字符串类型在 go 里是个结构, 包含指向底层数组的指针和长度,这两部分每部分都是 8 个字节,所以字符串类型大小为 16 个字节。

4. iota 常量

iota 特殊常量,可以认为是一个可以被编译器修改的常量。

iota 在 const 关键字出现时将被重置为 0 (const 内部的第一行之前)const 中每新增一行常量声明将使iota 计数一次 ( iota 可理解为 const 语句块中的行索引)。

iota 可以被用作枚举值:

const (
    a = iota
    b = iota
    c = iota
)

第一个 iota 等于 0每当 iota 在新的一行被使用时,它的值都会自动加 1 ;所以 a=0, b=1, c=2 可以简写为如下形式:

const (
    a = iota
    b
    c
)

使用示例:

package main

import "fmt"

func main() {
    const (
            a = iota   //0
            b          //1
            c          //2
            d = "ha"   //独立值iota += 1
            e          //"ha"   iota += 1
            f = 100    //iota +=1
            g          //100  iota +=1
            h = iota   //7,恢复计数
            i          //8
    )
    fmt.Println(a,b,c,d,e,f,g,h,i)
}

// 输出结果为:
// 0 1 2 ha ha 100 100 7 8

4.1. const 作用域只在当前的括号范围内

iota 的含义是初始化一个计数器,这个计数器的影响范围只能是 const 后括号作用域范围内的常量。

package main

import (
    "fmt"
)

func main() {
    const (
        a = iota
        b
        c
        d
        e
    )
    const (
        A = iota
        B
        C
        D
    )
    fmt.Println(a, b, c, d, e)
    fmt.Println(A, B, C)
}

// 输出结果如下:
// 0 1 2 3 4
// 0 1 2

iota 把初始值 0 赋给 a 后,自增 1此时 iota 等于1随后将 1 赋值给常量 b赋值完成后iota 又自增 1此时 iota 等于2这个自增过程只会出现在 const 后括号范围内,超过这个括号作为域。再次使用 iota 时,其初始值为 0。从输出结果可知常量 A 从 0 开始,可以证实这个观点。

4.2. const 作用域内iota 自增 1

package main

import (
    "fmt"
)

func main() {
    const (
        NUM1 = iota
        NUM2
        NUM3 = iota
        NUM4
        NUM5
    )
    const (
        A = iota
        B
        C
        D
    )
    fmt.Println(NUM1, NUM2, NUM3, NUM4, NUM5)
    fmt.Println(A, B, C)
}

// 输出信息是:
// 0 1 2 3 4
// 0 1 2

4.3. iota 不会自动初始化括号作用域内 iota 前边的常量

// 错误示例代码
func main() {
    const (
        a 
        b
        c = iota
        d
        e
    )
    fmt.Println(a, b, c, d, e)
}

编译时产生的错误信息:

./hello.go:9:9: missing value in const declaration
./hello.go:10:9: missing value in const declaration
./hello.go:15:17: undefined: a
./hello.go:15:20: undefined: b

从上边的示例代码中可以得知iota 并不会给括号作用域范围内使用 iota 赋值的那个常量之前的常量赋值,只会给括号作用域内使用 iota 初始化的那个常量后边的所有常量自增 1 后赋值。

4.4. 设定从某个特定初始值开始

iota 默认初始值为 0我们可以定义的常量初始值从 10 开始,代码如下:

func main() {
    const (
        a = 10 + iota
        b
        c
        d
        e
    )
    fmt.Println(a, b, c, d, e)
}

// 输出结果:
// 10 11 12 13 14

当使用带 iota 的表达式初始化常量时括号作用域内后边的常量在初始化时也会使用这个表达式进行初始化。相当于初始化表达式是10+1b 初始化的值是10+2以此类推。整个初始化过程中依然是 iota 在自增 1。

4.5. const 常量带有多个 iota 表达式

func main() {
    const (
        a = iota + 10
        b = iota
        c = iota + 5
        d
        e
    )
    fmt.Println(a, b, c, d, e)
}

// 输出信息是:
// 10 1 7 8 9

从上边的输出信息可以得知,在使用表达式初始化常量时,会使用离被初始化常量前边最近的那个表达式。如初始化 c 时,使用的是 2+5初始化 b 时,使用的是 iota此时的 iota 值为 1。

5. 定义常量组不设置初始值

在定义常量组时,如果不提供初始值,则表示将使用上行的表达式值。

package main

import "fmt"

const (
    a = 1
    b
    c
    d
)

func main() {
    fmt.Println(a)
    // b、c、d没有初始化使用上一行(即a)的值
    fmt.Println(b)   // 输出1
    fmt.Println(c)   // 输出1
    fmt.Println(d)   // 输出1
}