• Go基础系列:常量和变量


    常量(Constants)和iota

    常量包含不会发生更改的数据。常量的数据类型只能是boolean、number(int/float/complex)或string。

    定义方式:

    const NAME [TYPE] = VALUE
    

    TYPE基本可以省略,因为常量都是简单数据类型,编译器可以根据值推断出它的数据类型。

    例如:

    const Pi = 3.14159
    

    常量在编译期间被评估,因此定义的常量必须是在编译期间就能计算出来的结果。例如调用一些运行期间的函数来生成常量的值就是错误的,因为在编译期间无法调用这些运行期间的函数。常量的值定义好后,无法在运行期间更改,否则会报错。

    const c = 3+2          // 正确
    const d = getNumber()  // 错误
    

    常量的精度可以随意长,Go不会出现精度溢出的问题。且常量赋值时,如果值太长,可以使用续行符

    const Ln2= 0.693147180559945309417232121458
                176568075500134360255254120680009
    const Log2E= 1/Ln2
    const Billion = 1e9
    

    Go中只有将超出变量精度的值赋值给变量时才会出现溢出问题。

    可以一次性定义多个常量:

    const beef, two, c = "meat", 2, "veg"
    const Monday, Tuesday, Wednesday = 1, 2, 3
    const (
        Monday, Tuesday, Wednesday = 1, 2, 3
        Thursday, Friday, Saturday = 4, 5, 6
    )
    

    常量可以用枚举。定义了下面的常量后,Female就代表了数值1。

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

    可以使用iota实现枚举,iota自身是builtin包中定义的一个常量,其值为0,它用于在常量中定义序列数,从0开始增加:

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

    iota第一次调用时,产生数值0,在新行中再次调用iota,将自动增加1,所以上面的a=0,b=1,c=2。上面的常量枚举可以简写成等价形式:

    const (
        a = iota
        b
        c
    )
    

    iota不能用于运行期间,因为它是小写字母开头的常量,不会被导出。下面的代码会报错:iota未定义

    var a int = iota
    

    iota也可以用于表达式中,例如iota+50表示将当前的iota值加上50。

    每个常量块(const block)结构都会重置和初始化iota的值为0

    func main() {
    	const a = iota           // a=0
    	const b = iota + 3       // b=3
    	const c,d = iota,iota+3  // c=0,d=3
    	const (
    		e = iota           // e=0
    		f = iota + 4       // f=5
    		g                  // g=6
    	)
    	println(a,b,c,d,e,f,g)
    }
    

    变量

    在使用变量之前,有两个过程:声明变量、变量赋值。声明变量也常被称为"定义变量"。变量声明后必须使用,否则会报错。

    定义变量的常用方式:

    var identifier type
    

    例如:

    var a int
    var b bool
    var str string
    
    // 或者
    var (
        a int
        b bool
        str string
    )
    

    当变量声明的时候,会做默认的赋0初始化,每种数据类型的默认赋0初始化的0值不同。例如int类型的0值为数值0,float的0值为0.0,string类型的0值为空"",bool类型的0值为false,数据结构的0值为nil,struct的0值为字段全部赋0。

    变量在编译期间就可以获取到它的值,但如果赋值给变量的值需要经过运行期间的计算,则需要延迟到运行期间才能获取对应的值。

    var a int = 15     // 编译期间赋值好
    var b int = 15/3   // 编译期间赋值好
    var c = getNumber() // 运行期间才赋值
    

    声明和赋值可以结合:

    var a int = 15
    var i = 5
    var b bool = false
    var str string = "Hello World"
    

    声明和赋值结合的时候,对于简单数据类型的值,可以省略type部分,因为Go可以根据值自己推断出类型:

    var a = 15
    var b = false
    var str = "Hello World"
    
    var (
        a = 15
        b = false
        str = "Hello World"
        numShips = 50
        city string
    )
    

    因为要推断数据类型,所以类型推断操作是在运行期间完成的。

    在使用推断类型的赋值时,如果想要指定特定类型,需要显式指定。例如整数数值推断的类型为int,要想让它保存到int64中,则必须显式指定类型:

    var a int64 = 2
    

    要推断类型必须是声明和赋值一起的,否则没有值,无法根据值去推断。例如var a是错的。

    除了上面的推断方式,通过:=符号也能实现声明和赋值结合,它也会根据数据类型进行推断,连var关键字都省略了:

    a := 50
    

    但是:=只能在函数代码块内部使用,在全局作用域下使用将报错,因为类型推断是在运行期执行的,而全局范围内的变量声明部分是在编译期间就决定好的。例如,下面的将报错:

    a := 10
    func main() { println(a) }
    

    变量声明之后不能再次声明(除非在不同的作用域),之后只能使用=进行赋值。例如,执行下面的代码将报错:

    package main
    
    import ("fmt")
    
    func main(){
    	x:=10
    	fmt.Println("x =",x)
    	x:=11
    	fmt.Println("x =",x)
    }
    

    错误如下:

    # command-line-arguments
    .	est.go:8:3: no new variables on left side of :=
    

    报错信息很明显,:=左边没有新变量。

    如果仔细看上面的报错信息,会发现no new variables是一个复数。实际上,Go允许我们使用:=一次性声明、赋值多个变量,而且只要左边有任何一个新变量,语法就是正确的。

    func main(){
        name,age := "longshuai",23
        fmt.Println("name:",name,"age:",age)
        
        // name重新赋值,因为有一个新变量weight
        weight,name := 90,"malongshuai"
        fmt.Println("name:",name,"weight:",weight)
    }
    

    需要注意,name第二次被:=赋值,Go第一次推断出该变量的数据类型之后,就不允许:=再改变它的数据类型,因为只有第一次:=对name进行声明,之后所有的:=对name都只是简单的赋值操作。

    例如,下面将报错:

    weight,name := 90,80
    

    错误信息:

    .	est.go:11:14: cannot use 80 (type int) as type string in assignment
    

    另外,变量声明之后必须使用,否则会报错,因为Go对规范的要求非常严格。例如,下面定义了weight但却没使用:

    weight,name := 90,"malongshuai"
    fmt.Println("name:",name)
    

    错误信息:

    .	est.go:11:2: weight declared and not used
    

    变量作用域(scope)

    Go语言的作用域采用的是词法作用域,意味着文本段定义所在位置决定了可看见的值范围。关于词法作用域和动态作用域,详细内容参见:一文搞懂:词法作用域、动态作用域、回调函数、闭包

    • 定义在函数内部的变量为局部变量,只在函数内部可见
    • 定义在代码块内(如{...CODE...})的变量也是局部变量,除了代码块就消失
    • 定义在代码块外、函数外的变量为包变量或者全局变量,它们可以被同一个目录下同一个包的多个文件访问(因为Go中一个目录下只能定义一个包,但一个包可以分成多个文件)
      • 如果变量的名称以小写字母开头,则其它包不能访问该变量
      • 如果变量的名称以大写字母开头,则其它包可以访问该变量

    不同scope的变量名可以冲突,但建议采取名称唯一的方式为变量命名。

  • 相关阅读:
    街边的泥人张
    没事试试50mm1.4
    WWOOF介绍一下,但貌似我们利用不了
    护照和签证
    071205还是晴photo
    忘年旅行
    12月6日大雪
    12月5日
    周六
    071204 晴
  • 原文地址:https://www.cnblogs.com/f-ck-need-u/p/9863108.html
Copyright © 2020-2023  润新知