04. Go 变量

变量主要用来存储数据信息,变量的值可以通过变量名进行访问。Go语言的变量名的命名规则与其他语言一样,都是由字母、数字和下画线组成,其中变量名的首字符不能为数字。常见的变量的数据类型包括整型、浮点型、布尔型及结构体等。

1、变量的声明

变量的声明通常使用var关键字,变量的声明格式如下:var identifier type

var a int          			//声明整型类型的变量,保存整数数值
var b string       			//声明字符串类型的变量
var c []float32    			//声明32位浮点切片类型的变量,浮点切片表示由多个浮点类型组成的数据结构
var d func() bool  			//声明返回值为布尔类型的函数变量
var e struct {     			//声明结构体类型的变量,该结构体拥有整型的x字段    
    x int
}

注意:Go语言和其他编程语言不同之处在于,它在声明变量时将变量的类型放在变量的名称之后。这样做的好处就是可以避免出现含糊不清的声明形式。例如,如果想要两个变量都是指针,不需要将它们分开书写,写成var a, b *int即可。

同样,可以一次声明多个变量。在声明多个变量时可以写成常量的那种形式,例如:

var (
    a int
    b string
    c []float32
    d func() bool
    e struct {
        x int
    }
)
  • 同一类型的多个变量可以声明在同一行,例如:var a, b, c int
  • 多个变量可以在同一行进行声明和赋值,例如:var a, b, c int = 1, 2, 3
  • 多个变量可以在同一行进行赋值,但注意只能在函数体内,例如:a, b = 1, 2
  • 如果想要交换两个变量的值,可以使用交换语句,例如:a, b = b, a
2、初始化变量

Go语言在声明变量时,自动对变量对应的内存区域进行初始化操作。每个变量会初始化其类型的默认值,例如:

  • 整型和浮点型变量的默认值为0。
  • 字符串变量的默认值为空字符串。
  • 布尔型变量的默认值为false。
  • 切片、函数、指针变量的默认值为nil。

变量的初始化标准格式如下:var 变量名 类型 = 表达式

a. 编译器推导类型的格式

2和int同为int类型,因此可以进一步简化初始化的写法,即var a = 2

等号右边的部分在编译原理里被称为右值(rvalue)

var attack = 35
var defence = 15
var damageRate float32 = 0.28
var damage = float32(attack+defence) * damageRate
fmt.Println(damage)
  • 第1行和第2行,右值为整型,attack和defence变量的类型为int。
  • 第3行,表达式的右值中使用了0.28。Go语言和C语言一样,这里如果不指定damageRate变量的类型,Go语言编译器会将damageRate类型推导为float64,由于这里不需要float64的精度,所以需要强制指定类型为float32。
  • 第4行,将attack和defence相加后的数值结果依然为整型,使用float32()将结果转换为float32类型,再与float32类型的damageRate相乘后,damage类型也是float32类型。
  • 第5行,输出damage的值。
b. 短变量声明并初始化

var的变量声明还有一种更为精简的写法,即a = 2

  • 其中,:=只能出现在函数内(包括在方法内),此时Go编译器会自动进行数据类型的推断。
  • 注意:由于使用了:=,而不是赋值的=,因此推导声明写法的左值变量必须是没有定义过的变量。若再次定义,将会出现编译错误。

该写法同样支持多个类型变量同时声明并赋值,例如:a, b := 1, 2

Go语言中,除了可以在全局声明中初始化实体,也可以在init函数中初始化。init函数是一个特殊的函数,它会在包完成初始化后自动执行,执行优先级比main函数高,并且不能手动调用init函数。每一个源文件有且只有一个init函数,初始化过程会根据包的依赖关系按顺序单线程执行。

可以在开始执行程序之前通过init函数来对数据进行检验与修复,保证程序执行时状态正常,例如:

package main

import (
	"fmt"
	"math"
)

// Pi 为圆周率
var Pi float64

func init() {
	Pi = 4 * math.Atan(1) // 在init函数中计算Pi的值
}

func main() {
	DPi := Pi * Pi
	fmt.Println(Pi, DPi)
}

3、多个变量同时赋值

变量的交换是编程最简单的算法之一。在进行交换变量时,通常需要一个中间变量临时对变量进行保存。用传统方法编写变量交换代码如下:

var a int = 100
var b int = 200
var t int
t = a
a = b
b = t
fmt.Println(a, b)

传统方法的变量交换往往占用了较大的内存空间,因此,根据这一情况又发明了一些算法来避免使用中间变量,例如:

var a int = 100
var b int = 200
a = a ^ b
b = b ^ a
a = a ^ b
fmt.Println(a, b)

这种算法往往对数值范围和类型都有一定的要求。到了Go语言时,内存不再是紧缺资源,而且写法可以更加简单。使用Go语言的“多重赋值”特性,可以轻松完成变量交换的任务,例如:

var a int = 100
var b int = 200
a, b = b, a
fmt.Println(a, b)

在对多个变量同时赋值时,变量的左值和右值按从左到右的顺序依次赋值。多重赋值在Go语言的错误处理和函数返回值中会大量地使用。例如,使用Go语言进行排序时就需要使用变量的交换,代码如下:

type IntSlice []int

func (p IntSlice) Len() int  {
	return len(p)
}
func (p IntSlice) Less(i, j int) bool {
	return p[i] < p[j]
}
func (p IntSlice) Swap(i, j int)  {
	p[i], p[j] = p[j], p[i]
}
  • 第1行,将IntSlice声明为[]int类型。
  • 第3行,为IntSlice类型编写一个Len方法,提供切片的长度。
  • 第6行,根据提供的i、j元素索引,获取元素后进行比较,返回比较结果。
  • 第9行,根据提供的i、j元素索引,交换两个元素的值
4、匿名变量

在编码过程中,可能会遇到没有名称的变量、类型或方法。虽然这不是必需的,但有时候这样做可以极大地增强代码的灵活性,这些变量被统称为匿名变量。

匿名变量可以用下画线(“_”)表示,而“_”本身就是一个特殊的标识符,因此被称为空白标识符。它可以像其他标识符那样用于变量的声明或赋值(任何类型都可以赋值给它),但任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用,也不可以使用这个标识符作为变量对其他变量进行赋值或运算。使用匿名变量时,只需要在变量声明的地方使用下画线替换即可。

func GetData() (int, int) {
	return 100, 50
}
func main() {
	a, _ := GetData()
	_, b := GetData()
	fmt.Println(a, b)
}
  • GetData()是一个函数,拥有两个整型返回值。每次调用将会返回100和50两个数值。
  • 第5行只需要获取第一个返回值,所以将第二个返回值的变量设为下画线(匿名变量)。
  • 第6行将第一个返回值的变量设为匿名变量。
5、变量作用域

一个变量(常量、类型或函数)在程序中都有一定的作用范围,该作用范围被称为作用域。

  • 函数内定义的变量称为局部变量。
  • 函数外定义的变量称为全局变量。
  • 函数定义中的变量称为形式参数。
a. 局部变量

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

局部变量不是一直存在的,它只在定义它的函数被调用后存在,函数调用结束后这个局部变量就会被销毁。

func main() {    
    //声明局部变量a 和 b 并赋值    
    var a int = 5    
    var b int = 3    
    //声明局部变量c 并计算 a 和 b 的和    
    c := a + b   
    fmt.Printf("a = %d, b = %d,c= %d\n", a, b, c)
}
b. 全局变量

在函数体外声明的变量称为全局变量,全局变量只需要在一个源文件中定义,就可以在所有源文件中使用。当然,不包含这个全局变量的源文件需要使用import关键字引入全局变量所在的源文件之后才能使用这个全局变量。

全局变量声明必须以var关键字开头,如果想要在外部包中使用,全局变量的首字母必须大写。

//声明全局变量
var c int
func main() {    
    //声明局部变量
    var a, b int   
    //初始化参数   
    a = 5    
    b = 3    
    c = a + b    
    fmt.Printf("a = %d, b= %d, c = %d\n", a, b, c)
}
  • Go语言程序中全局变量与局部变量名称可以相同,但是函数体内的局部变量会被优先考虑。
c. 形式参数

在定义函数时,函数名后面括号中的变量称为形式参数(简称形参)。形式参数只在函数调用时才会生效,函数调用结束后就会被销毁。在函数未被调用时,函数的形参并不占用实际的存储单元,也没有实际值。形式参数会作为函数的局部变量来使用。

func main() {
	var a int = 10
	var b int = 20
	var c int = 0
	fmt.Printf("main()函数中 a=%d\n", a)
	c = sum(a, b)
	fmt.Printf("main()函数中 c = %d\n", c)

}

/*函数定义-两数相加*/
func sum(a, b int) int {
	fmt.Printf("sum() 函数中 a = %d\n", a)
	fmt.Printf("sum() 函数中 b = %d\n", b)
	return a + b
}

你可能感兴趣的:(Go语言从入门到实践,golang)