• 换个语言学一下 Golang (4)——变量与常量


    一、变量定义

    所谓的变量就是一个拥有指定名称类型数据存储位置

    //看一个例子
    package main
    import (
        "fmt"
    )
    func main() {
        var x string = "hello world"
        fmt.Println(x)
    }
    View Code

    变量的定义首先使用var关键字,然后指定变量的名称x,再指定变量的类型string,在本例中,还对变量x进行了赋值,然后在命令行输出该变量。Go这种变量定义的方式和其他的语言有些不同,但是在使用的过程中,你会逐渐喜欢的。当然上面的变量定义方式还可以如下,即先定义变量,再赋值。

        var x string
        x = "hello world"

    或者是直接赋值,让Go语言推断变量的类型。如下:

    var x = "hello world"

    当然,上面变量的定义还有一种快捷方式。如果你知道变量的初始值,完全可以像下面这样定义变量,完全让Go来推断语言的类型。这种定义的方式连关键字var都省略掉了。

    x := "hello world"

    注意:上面这种使用:=方式定义变量的方式只能用在函数内部

    package main
    import (
        "fmt"
    )
    x:="hello world"
    func main() {
        y := 10
        fmt.Println(x)
        fmt.Println(y)
    }

    对于上面的变量定义x是无效的。会导致编译错误:

    ./test_var_quick.go:7: non-declaration statement outside function body

    不过我们对上面的例子做下修改,比如这样是可以的。也就是使用var关键字定义的时候,如果给出初始值,就不需要显式指定变量类型。

    package main
    import (
        "fmt"
    )
    var x = "hello world"
    func main() {
        y := 10
        fmt.Println(x)
        fmt.Println(y)
    }

    变量之所以称为变量,就是因为它们的值在程序运行过程中可以发生变化,但是它们的变量类型是无法改变的。因为Go语言是静态语言,并不支持程序运行过程中变量类型发生变化。比如如果你强行将一个字符串值赋值给定义为int的变量,那么会发生编译错误。即使是强制类型转换也是不可以的。强制类型转换只支持同类的变量类型。比如数值类型之间强制转换。

    下面我们看几个例子:

    package main
    import (
        "fmt"
    )
    func main() {
        var x string = "hello world"
        fmt.Println(x)
        x = "i love go language"
        fmt.Println(x)
    }

    本例子演示变量的值在程序运行过程中发生变化,结果输出为

    hello world
    i love go language

    我们尝试不同类型的变量之间转换

    package main
    import (
        "fmt"
    )
    func main() {
        var x string = "hello world"
        fmt.Println(x)
        x = 11
        fmt.Println(x)
    }

    在本例子中,如果试图将一个数值赋予字符串变量x,那么会发生错误:

    ./test_var.go:10: cannot use 11 (type int) as type string in assignment

    上面的意思就是无法将整型数值11当作字符串赋予给字符串变量。

    但是同类的变量之间是可以强制转换的,如浮点型和整型之间的转换。

    package main
    import (
        "fmt"
    )
    func main() {
        var x float64 = 32.35
        fmt.Println(x)
        fmt.Println(int(x))
    }

    输出的结果为

    32.35
    32

    二、变量命名

    上面我们看了一些变量的使用方法,那么定义一个变量名称,有哪些要求呢?
    这里我们要注意,Go的变量名称必须以字母或下划线(_)开头,后面可以跟字母,数字,或者下划线(_)。除此之外,Go语言并不关心你如何定义变量。我们通用的做法是定义一个用户友好的变量。假设你需要定义一个狗狗的年龄,那么使用dog_age作为变量名称要好于用x来定义变量。

    三、变量作用域

     现在我们再来讨论一下变量的作用域。所谓作用域就是可以有效访问变量的区域。比如很简单的,你不可能在一个函数func_a里面访问另一个函数func_b里面定义的局部变量x。所以变量的作用域目前分为两类,一个是全局变量,另一个是局部变量。下面我们看个全局变量的例子:

    package main
    import (
        "fmt"
    )
    var x string = "hello world"
    func main() {
        fmt.Println(x)
    }

    这里变量x定义在main函数之外,但是main函数仍然可以访问x。全局变量的作用域是该包中所有的函数。

    package main
    import (
        "fmt"
    )
    var x string = "hello world"
    func change() {
        x = "i love go"
    }
    func main() {
        fmt.Println(x)
        change()
        fmt.Println(x)
    }

    在上面的例子用,我们用了change函数改变了x的值。输出结果如下:

    hello world
    i love go

    我们再看一下局部变量的例子。

    package main
    import (
        "fmt"
    )
    func change() {
        x := "i love go"
    }
    func main() {
        fmt.Println(x)
    }

    该例子中main函数试图访问change函数中定义的局部变量x,结果发生了下面的错误(未定义的变量x):

    ./test_var.go:11: undefined: x

    三、常量

    Go语言也支持常量定义。所谓常量就是在程序运行过程中保持值不变的变量定义。常量的定义和变量类似,只是用const关键字替换了var关键字,另外常量在定义的时候必须有初始值

    package main
    import (
        "fmt"
    )
    func main() {
        const x string = "hello world"
        const y = "hello world"
        fmt.Println(x)
        fmt.Println(y)
    }

    这里有一点需要注意,变量定义的类型推断方式:=不能够用来定义常量。因为常量的值是在编译的时候就已经确定的,但是变量的值则是运行的时候才使用的。这样常量定义就无法使用变量类型推断的方式了。

    常量的值在运行过程中是无法改变的,强制改变常量的值是无效的。

    我们看一个Go包math里面定义的常量Pi,用它来求圆的面积。

    package main
    import (
        "fmt"
        "math"
    )
    func main() {
        var radius float64 = 10
        var area = math.Pow(radius, 2) * math.Pi
        fmt.Println(area)
    }

    四、多变量或常量定义

    Go还提供了一种同时定义多个变量或者常量的快捷方式。

    package main
    import (
        "fmt"
    )
    func main() {
        var (
            a int     = 10
            b float64 = 32.45
            c bool    = true
        )
        const (
            Pi   float64 = 3.14
            True bool    = true
        )
        fmt.Println(a, b, c)
        fmt.Println(Pi, True)
    }

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

    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
    }

    五、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
    )

    iota 用法

    实例 

    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

    再看个有趣的的 iota 实例: 

    package main
    
    import "fmt"
    const (
        i=1<<iota
        j=3<<iota
        k
        l
    )
    
    func main() {
        fmt.Println("i=",i)
        fmt.Println("j=",j)
        fmt.Println("k=",k)
        fmt.Println("l=",l)
    }

    以上实例运行结果为: 

    i= 1
    j= 6
    k= 12
    l= 24

    ota 表示从 0 开始自动加 1,所以 i=1<<0, j=3<<1(<< 表示左移的意思),即:i=1, j=6,这没问题,关键在 k 和 l,从输出结果看 k=3<<2,l=3<<3。

    简单表述:

    i=1

      :左移 0 位,不变仍为 1;
    • j=3:左移 1 位,变为二进制 110, 即 6;
    • k=3:左移 2 位,变为二进制 1100, 即 12;
    • l=3:左移 3 位,变为二进制 11000,即 24。
  • 相关阅读:
    动态SQL语句
    Mybatis配置和基于配置的使用
    JQuery封装的ajax、ajax上传文件、JSON对象
    Jsp生命周期、Jsp的使用、JSP隐式对象、EL表达式、JSTL
    原生Ajax
    Servlet上传文件、会话跟踪、Cookies和session的使用及其常用方法
    ResponseBodyAdvice拦截Controller方法默认返回参数,统一处理返回值/响应体
    钉钉机器人
    花瓶安装和使用
    方法入参检测工具类 spring自带org.springframework.util.Assert 通用类
  • 原文地址:https://www.cnblogs.com/tianyamoon/p/11083450.html
Copyright © 2020-2023  润新知