Go中的常量

606 阅读4分钟

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战

常量

在程序的运行过程中不能被改变的量, 我们称之为常量.

常量通常用来存储在程序的运行过程中, 不会被改变的值.

常量的定义格式 const xxx [type] = value

常量的分类

用户定义的常量

我们可以使用const关键字来定义一个常量

字面量

字面常量, 又称为字面量, 用于表达源代码中一个固定的值的称呼

像布尔类型: true, false, 所有的数字2, 3.14等, 所有的被双引号引起来的字符串"hi", "go"等, 它们的值就是它们自己, 所以这些又被为字面量

常量的定义

  • 显式类型定义常量
 // 显式类型定义一个常量
 const pi float64 = 3.14
 fmt.Println(pi)
  • 隐式类型定义常量
 // 在定义常量的时候, 类型修饰符是可以省略的
 // 编译器在编译的时候, 会根据上下文来进行推断其类型
 // 隐式类型推断
 const age = 18
 fmt.Println(18)
 ​
 // 常量在定义好之后是不可修改的
 // 编译报错: cannot assign to xxx (declared const)
 // age = 15

特殊常量 iota

iota是一个特殊的常量, 在每次const出现时, iota的值就会被重置为0

iota每出现一次, iota的值自动加1, 直到遇到一个const, 值被置为0

 // iota出现一次, 值自动加1
 const (
    a = iota
    b = iota
    c = iota
 )
 fmt.Println(a, b, c) // 输出结果为: 0, 1, 2
 ​
 // 可以简写为这样
 const (
    d = iota
    e
    f
 )
 fmt.Println(d, e, f) // 输出结果为: 0, 1, 2
 ​
 // 在使用块定义常量的时候, 第一个常量必须赋值
 // 如果后面的常量没有被赋值, 则继承上个常量的值
 const (
    h = iota
    /*
    这里i没有被赋值, 则继承它上个常量的值
    这里的语句相当于 i = iota
    上个iota的值为0, 因此i这里的iota值自动加1, 为1
    */
    i
    j = 8
    k
 )
 fmt.Println(h, i, j, k) // 输出结果为: 0, 1, 8, 8
 ​
 // 这里iota的值, 又被重置为0
 const z = iota
 fmt.Println(z)

无类型的常量

 // 无类型常量, 可以赋值给其它与其类型兼容的变量
 const value = 18
 ​
 // 可以将一个无类型常量赋值给int类型的变量
 var intValue int = value
 ​
 // 可以将一个无类型常量赋值给float64类型的变量
 var floatValue float64 = value
 ​
 // 输出结果: int - 18, float64 - 18
 fmt.Printf("%s - %#v", reflect.TypeOf(intValue), intValue)
 fmt.Printf("%s - %#v", reflect.TypeOf(floatValue), floatValue)

作用域

限定标识符可用性的代码范围, 就是这个标识符的作用域

作用域可以提高程序逻辑的局部性, 程序的可靠性, 减少标识识冲突

全局变量

在函数体外声明变量称为全局变量, 它的作用范围在以下地方都可使用

在当前文件中

在当前文件的函数中

在当前包中的多个文件中

导出后, 在外部包的文件中

局部变量

在函数体内或代码块内声明的变量称为局部变量, 它的作用范围在以下地方都可使用

在声明它的函数体内

在声明它的代码块内

代码块

一对大括号{}内部的代码称为代码块

常见的代码块

if语句代码块

 /*
 在整个if语句结构中都可以使用
 */
 if age := 15; age > 18 {
    fmt.Println("是个大人了, 年龄: ", age)
 } else {
    fmt.Println("还是个小孩, 年龄: ", age)
 }

for循环体代码块

 // for
 // 在整个循环体的代码块是可以使用的
 for i := 0; i < 10; i++ {
    fmt.Println("当前索引: ", i)
 }

func函数体代码块

 // 函数体
 /*
 函数参数, 函数返回值, 函数内定义的变量
 只有在函数体才可使用
 */
 func hi(name string) (sayHi string)  {
    return "hi, " + name
 }

{}纯代码块

在编写代码的时候, 我们有时候也会使用大括号来进行代码的控制和作用域的划分

我们通过一段代码来感受一下作用域

 // 全局变量
 var (
    globalValue = 1
 )
 ​
 func main() {
    // globalValue的值为1
    fmt.Println(globalValue)
 ​
    globalValue := 3
    // globalValue的值为3
    fmt.Println(globalValue)
 ​
    {
       globalValue := 5
       // globalValue的值为5
       fmt.Println(globalValue)
 ​
       {
          globalValue := 7
          // globalValue的值为7
          fmt.Println(globalValue)
       }
 ​
       // globalValue的值为5
       fmt.Println(globalValue)
    }
    
    // globalValue的值为3
    fmt.Println(globalValue)
 }

注意: 在进行变量命名的时候

全局变量一般下划线开头, 字母驼峰命名,

全局常量一般全部大写, 下划线命名.

局部变量一般使用驼峰命名

总结

Go语言中有各种各样的变量常量定义方式, 可以分开定义, 可以集中定义, 可以分开赋值, 可以平行赋值. 还有一个特殊的常量iota, 可以定义一个无类型的常量, 可以赋值给与它兼容的变量. Go语言中的作用域比其它语言相差不大, 也略有不同. 一个全局变量, 不但可以跨文件使用, 还可以跨包使用, 相当灵活. 总之使用Go之后, 有一种相见恨晚的感觉!!!