zoukankan      html  css  js  c++  java
  • Go变量、常量和作用域

    变量

    变量是几乎所有编程语言中最基本的组成元素。从根本上说,变量相当于是对一块数据存储空间的命名,程序可以通过定义一个变量来申请一块数据存储空间,之后可以通过引用变量名来使用这块存储空间。

    var声明语句可以创建一个特定类型的变量,然后给变量附加一个名字,并且设置变量的初始 值。变量声明的一般语法如下:

    var 变量名字 类型 = 表达式
    定义变量并进行初始化,例如:var name string = "silence"
    
    var 变量名 变量类型
    定义变量使用零值进行初始化,例如:var age int
    
    var 变量名 = 值
    定义变量,变量类型通过值类型进行推导.例如: var isBoy = true
    
    var 变量名 1, 变量名 2 , …, 变量名 n 变量类型
    定义多个相同类型的变量并使用零值进行初始化.例如:var prefix, suffix string
    
    var 变量名 1, 变量名 2 , …, 变量名 n 变量类型 = 值 1, 值 2, …, 值 n
    定义多个相同类型的变量并使用对应的值进行初始化,例如:var prev, next int = 3, 4
    
    var 变量名 1, 变量名 2 , …, 变量名 n = 值 1, 值 2, …, 值 n
    定义多个变量并使用对应的值进行初始化,变量的类型使用值类型进行推导,类型可不相同,例如:var name, age = "silence", 30
    
    批量定义
    var (
        变量名 1 变量类型 1 = 值 1
        变量名 2 变量类型 2 = 值 2 
    )
    定义多个变量并进行初始化,批量复制中变量类型可省略
    例如:
    var (
        name string = "silence"
        age int = 30
    )
    

    初始化表达式可以使用字面量、任何表达式、函数

    package main
    
    import "fmt"
    
    var v0 int
    var v1 int = 1
    var v2 = 2
    
    var v3, v4 int = 3, 4
    
    var v5, v6 = "5", 6
    
    func main() {
    	var (
    		v7 int = 2 + 5
    		v8 int = v2 + v6
    	)
    	fmt.Println(v0, v1, v2, v3, v4, v5, v6, v7, v8)	//0 1 2 3 4 5 6 7 8
    }
    

    简短变量声明

    在函数内部,有一种称为简短变量声明语句的形式可用于声明和初始化局部变量。它以“名字 := 表达式”形式声明变量,变量的类型根据表达式来自动推导。

    t := 0.0
    i := 100	// 注意等号前的冒号
    
    简式声明一般用在func内,要注意的是:全局变量和简式声明的变量尽量不要同名,否则很容易产生偶然的变量隐藏
    

    即使对于经验丰富的Go开发者而言,这也是一个非常常见的陷阱。这个坑很容易挖,但又很难发现。

    func main() {  
        x := 1
        fmt.Println(x)     // 1
        {
            fmt.Println(x) //  1
            x := 2
            fmt.Println(x) //  2
        }
        fmt.Println(x)     //  1 (不是2)
    }
    

    赋值

    想要交换两个变量的值,则可以简单地使用:

    a, b = b, a
    这样省去了使用交换函数的必要
    

    空白标识符

    空白标识符 也被用于抛弃值

    _, b = 5, 7	//5被抛弃
    

    _ 实际上是一个只写变量,你不能得到它的值。这样做是因为 Go 语言中你必须使用所有被声明的变量,但有时你并不需要使用从一个函数得到的所有返回值。

    由于Go语言有个强制规定,在函数内一定要使用声明的变量,但未使用的全局变量是没问题的。为了避免有未使用的变量,代码将编译失败,我们可以将该未使用的变量改为 _。

    另外,在Go语言中,如果引入的包未使用,也不能通过编译。有时我们需要引入的包,比如需要init(),或者调试代码时我们可能去掉了某些包的功能使用,你可以添加一个下划线标记符,_,来作为这个包的名字,从而避免编译失败。下滑线标记符用于引入,但不使用。

    package main
    import (  
        _ "fmt"
        "log"
        "time"
    )
    var _ = log.Println
    func main() {  
        _ = time.Now
    }
    

    零值nil

    nil 标志符用于表示interface、函数、maps、slices和channels的“零值”。如果你不指定变量的类型,编译器将无法编译你的代码,因为它猜不出具体的类型。

    package main
    func main() {  
        var x = nil // 错误
        _ = x
    }
    

    字符串不会为 nil

    var s string  = "" // ""是字符串的零值
    var str string	// 也是字符串的零值
    

    常量

    在Go语言中,常量是指编译期间就已知且不可改变的值。常量可以是数值类型(包括整型、浮点型和复数类型)、布尔类型、字符串类型等。

    字面常量

    所谓字面常量(literal),是指程序中硬编码的常量,如:

    -12		//整型 
    
    3.14159265358979323846 // 浮点类型的常量
    
    3.2+12i // 复数类型的常量
    
    true // 布尔类型的常量
    
    "foo" // 字符串常量
    

    在其他语言中,常量通常有特定的类型,比如-12在C语言中会认为是一个int类型的常量。如果要指定一个值为-12的long类型常量,需要写成-12l,这有点违反人们的直观感觉。Go语言的字面常量更接近我们自然语言中的常量概念,它是无类型的。只要这个常量在相应类型的值域范围内,就可以作为该类型的常量,比如上面的常量-12,它可以赋值给int、uint、int32、int64、float32、float64、complex64、complex128等类型的变量。

    常量定义

    常量用于定义不可被修改的的值,需要在编译过程中进行计算,只能为基础的数据类型布尔、数值、字符串,使用 const 进行常量声明,常量声明必须初始化值

    常用语法:

    const 常量名 类型 = 值
    定义常量并进行初始化,例如:const pi float64 = 3.1415926
    
    const 常量名 = 值
    定义常量,类型通过值类型进行推导,例如:const e = 2.7182818
    
    批量定义
    const (
    	常量名 1 类型 1 = 值 1 常量名 2 类型 2 = 值 2 
    	)
    定义多个变量并进行初始化,批量复制中变量类型可省略,并且除了第一个常量值外其他常量可同时省略类型和值,表示使用前一个常量的初始化表达式
    例如:
    const (
        name string = "silence"
        age int = 30
    )
    const (
        name string = "silence"
        desc
    )
    

    常量之间的运算,类型转换,以及对常量调用函数 len、cap、real、imag、complex、unsafe.Sizeof 得到的结果依然为常量

    package main
    
    import "fmt"
    
    const c0 int = 0
    
    const c1 int = 1
    const c2 = 3 -1
    const c3, c4 int = 3, 4
    const c5, c6 = "5", c4 + c2
    
    func main() {
    	const (
    		c7 int = 7
    		c8
    	)
    	fmt.Println(c0, c1, c2, c3, c4, c5, c6, c7, c8)	//0 1 2 3 4 5 6 7 7
    }
    

    枚举iota

    常使用iota生成器用于初始化一系列相同规则的常量,批量声明常量的第一个常量的使用iota进行赋值,此时 iota 被重置为 0,其他常量省略类型和赋值,在每初始化一个常量则加 1

    iota()以内从0开始,如果另一个()内也是iota,则重新从0开始

    const (
    	i1 int = iota
    	i2
    	i3 int = iota
    	i4
    )
    
    func main() {
    	//  枚举
    	const (
    		i5 = iota
    		i6
    		i7 = 7
    		i8 = iota
    		i9
    	)
    
    	fmt.Println(i1, i2, i3, i4, i5, i6, i7, i8, i9)	//0 1 2 3 0 1 7 3 4
    
    }
    

    作用域

    作用域指变量可以使用范围,就近原则。go 语言使用大括号显示的标识作用域范围,大括号内包含一连串的语句,叫做语句块。语句块可以嵌套,语句块内定义的变量不能在语句块外使用

    局部变量

    在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量。

    package main
    
    import "fmt"
    
    func main() {
       /* 声明局部变量 */
       var a, b, c int 
    
       /* 初始化参数 */
       a = 10
       b = 20
       c = a + b
    
       fmt.Printf ("结果: a = %d, b = %d and c = %d
    ", a, b, c)	//结果: a = 10, b = 20 and c = 30
    }
    
    

    全局变量

    作用域是全局的(在本包范围内)
    在函数体外声明的变量称之为全局变量,全局变量可以在整个包甚至外部包(被导出后)使用。全局变量可以在任何函数中使用。

    package main
    
    import "fmt"
    
    /* 声明全局变量 */
    var g int
    
    func main() {
    
       /* 声明局部变量 */
       var a, b int
    
       /* 初始化参数 */
       a = 10
       b = 20
       g = a + b
    
       fmt.Printf("结果: a = %d, b = %d and g = %d
    ", a, b, g)	//结果: a = 10, b = 20 and g = 30
    }
    

    简式变量

    使用 := 定义的变量,如果新变量p与那个同名已定义变量 (这里就是那个全局变量p)不在一个作用域中时,那么Go 语言会新定义这个变量p,遮盖住全局变量p。刚开始很容易在此犯错而茫然,解决方法是局部变量尽量不同名,限定标识符使用的范围。

    注意,简式变量只能在函数内部声明使用,但是它可能会覆盖函数外全局同名变量。而且你不能在一个单独的声明中重复声明一个变量,但在多变量声明中这是允许的,而且其中至少要有一个新的声明变量。重复变量需要在相同的代码块内,否则你将得到一个隐藏变量。
    
    如果你在代码块中犯了这个错误,将不会出现编译错误,但应用运行结果可能不是你所期望。所以尽可能避免和全局变量同名。
    

    常见隐式语句块

    	全语句块
    
    ​	包语句块
    
    ​	文件语句块
    
    ​	if、switch、for、select、case 语句块
    
    作用域内定义变量只能被声明一次且变量必须使用,否则编译错误。在不同作用域可定义相同的变量,此时局部将覆盖全局
    
    package main
    
    import "fmt"
    
    func main() {
    	outer := 1
    	{
    		inner := 2
    		fmt.Println(outer, inner)	//1 2
    		outer := 3
    		fmt.Println(outer, inner)	//3 2	寻找由内向外
    	}
    	//fmt.Println(inner)	//使用原则: 子语句块可以使用父语句块中的标识符,父不能用子的
    	fmt.Println(outer)	//1
    }
    

    形式参数

    形式参数会作为函数的局部变量来使用

    package main
    
    import "fmt"
    
    /* 声明全局变量 */
    var a int = 20;
    
    func main() {
       /* main 函数中声明局部变量 */
       var a int = 10
       var b int = 20
       var c int = 0
    
       fmt.Printf("main()函数中 a = %d
    ",  a);	//main()函数中 a = 10
       c = sum( a, b);
       fmt.Printf("main()函数中 c = %d
    ",  c);	//main()函数中 c = 30
    }
    
    /* 函数定义-两数相加 */
    func sum(a, b int) int {
       fmt.Printf("sum() 函数中 a = %d
    ",  a);	//sum() 函数中 a = 10
       fmt.Printf("sum() 函数中 b = %d
    ",  b);	//sum() 函数中 b = 20
    
       return a + b;
    }
    
  • 相关阅读:
    I.MX6 Surfaceflinger 机制
    理解 Android Fragment
    RPi 2B DDNS 动态域名
    RPi 2B IPC webcam server
    理解 Android MVP 开发模式
    I.MX6 system.img unpack repack
    can't set android permissions
    VMware Ubuntu 共享文件夹
    解决oracle数据库连接不上的问题
    perfect-scrollbar示例
  • 原文地址:https://www.cnblogs.com/Otiger/p/13703041.html
Copyright © 2011-2022 走看看