5 constants 常量

218 阅读5分钟

本文为译文。原文地址:constant

常量的声明

声明一个常量

package main

import (  
    "fmt"
)

func main() {  
    const a = 50
    fmt.Println(a)
}

声明一组常量

package main

import (  
    "fmt"
)

func main() {  
    const (
        name = "John"
        age = 50
        country = "Canada"
    )
    fmt.Println(name)
    fmt.Println(age)
    fmt.Println(country)

}

常量,顾名思义不可被二次赋值。同时常量的值在编译期就必须明确,不可在运行期在分配。

package main

func main() {  
    const a = 55 //allowed
    a = 89 //reassignment not allowed
    
    const b = math.Sqrt(4) //not allowed. when assigned a value to b in runtime
}

字符串常量、类型和非类型常量

在go里所有通过双引号包裹的值都是stirng 常量。例如"Hello World", "Sam" 在go中都是常量。

string常量属于什么类型?答案是untyped

一个string常量比如"hello world"是没有任何类型的。

const hello = "Hello World"  
//hello常量是没有任何类型的。 我们将其称为非类型常量			

GO是强类型语言,所有的变量都必须有一个明确的类型。我们看下面的程序

下面的程序为什么我们分配给变量name一个非类型常量n,也是可以工作的呢?

package main

import (  
    "fmt"
)

func main() {  
    const n = "Sam"
    var name = n
    fmt.Printf("type %T value %v", name, name)

}

答案是:untyped constant 会有一个与之相关的默认类型。只有当代码需要其时,其才会提供该类型。在第9行我们声明**var name = n**,name需要一个类型,然后它获取该类型从字符串常量n的默认类型string。(name needs a type and it gets it from the default type of the string constant n which is a string)

那我们如何能创建一个类型常量?

const typedhello string = "Hello World"  
//typedhello in the above code is a constant of type string.

GO是强类型语言,在赋值期间混合类型是不允许的。如下例

package main

func main() {  
        var defaultName = "Sam" //allowed
        type myString string
        var customName myString = "Sam" //allowed
        customName = defaultName //not allowed

}

上面的代码,我们首先创建了一个defaultName然后为其分配了一个常量"Sam"。常量Sam的默认类型是string。因此后边分配给defaultName的类型也是string

下一行,我们创建了一个类型叫myString即string的别名。

然后我们创建一个myString类型的变量customName然后为其分配一个值叫"Sam"。因为常量"Sam"是无类型的,所以其可以被分配给任何string类型的变量。

现在我们有一个string类型的变量defaultName和一个myString类型的变量customName。即使我们知道myString类型其实就是string类型的别名。但是还是报错了。Go的强类型策略,不允许将一个类型的变量值分配给另一个。因此赋值操作**customName = defaultName**是不被允许的,编译器在编译阶段就会报错**./prog.go:7:20: cannot use defaultName (type string) as type myString in assignment**

布尔常量

基本原则和字符串常量一致。

package main

func main() {  
    const trueConst = true
    type myBool bool
    var defaultBool = trueConst //allowed
    var customBool myBool = trueConst //allowed
    defaultBool = customBool //not allowed
}

数字常量

数字常量包含integers, floats and complex constants。在数字常量中和其他类型比有一些微妙之处。

package main

import (  
    "fmt"
)

func main() {  
    const a = 5
    var intVar int = a
    var int32Var int32 = a
    var float64Var float64 = a
    var complex64Var complex64 = a
    fmt.Println("intVar",intVar, "\nint32Var", int32Var, "\nfloat64Var", float64Var, "\ncomplex64Var",complex64Var)
}

intVar 5 
int32Var 5 
float64Var 5 
complex64Var (5+0i)

上面的const a是一个非类型的其值为5.你可能会思考**a的默认类型是什么,如果a只有一个默认类型,为什么可以赋值给不同类型的变量。答案就在于a的语法。**我们看下面的一个例子

package main

import (  
    "fmt"
)

func main() {  
    var i = 5
    var f = 5.6
    var c = 5 + 6i
    fmt.Printf("i's type is %T, f's type is %T, c's type is %T", i, f, c)

}

上面的程序,每一个变量的类型取决于数字常量的语法。5是一个整形、5.6是一个浮点型、5+6i是一个复数。当以上程序运行,打印如下

i's type is int, f's type is float64, c's type is complex128  

有了上面的知识,我们再来理解一下这个程序

package main

import (  
    "fmt"
)

func main() {  
    const a = 5
    var intVar int = a
    var int32Var int32 = a
    var float64Var float64 = a
    var complex64Var complex64 = a
    fmt.Println("intVar",intVar, "\nint32Var", int32Var, "\nfloat64Var", float64Var, "\ncomplex64Var",complex64Var)
}

上面的程序,a的值是5,a的类型是通用的(原文a的语法是通用的,感觉怪怪的 the value of a is 5 and the syntax of a is generic)。它可以代表一个float integer 甚至一个没有虚部的complex。因此其可以被分配给任何一个类型兼容的变量。这种常量的默认值可以被认为是根据上下文生成的。var intVar int = a要求a是一个是一个int型所以其变成了一个int常量 var complex64Var complex64 = a要求a是一个复数,因此a变成了一个复数产量。

数字表达式

在表达式中,数字类型可以任意混合。只有在赋值操作或者使用的时候才需要一个类型上的理解。

package main

import (  
    "fmt"
)

func main() {  
    var a = 5.9 / 8
    fmt.Printf("a's type is %T and value is %v", a, a)
}

上面的程序5.9是一个float类型8是一个integer。但是表达式 5.9 / 8是合法的语法。其结果为0.7375是一个float类型,所以变量a是一个float类型。程序输出如下

a's type is float64 and value is 0.7375