05 变量的声明与使用

变量

一 变量介绍

​ 程序的运行本质就是一系列状态的变化,比如:在游戏程序的运行过程中,一个角色的等级由0级升级到10级、金钱由10增长到了1000等。

​ 所以程序的开发语言中必须有一种机制/语法能够控制计算机记录下事物状态,并且该状态是可以发生变化的,这就是变量。

​ 变量是对“量”与“变”行为的抽象总结, “量”指的是记录下状态,“变”指的是记录的状态是可以发送变化的。状态是记录/存储到内存中的,又称之为数据,所以说每个变量都对应一块内存空间,而变量其实就像是一个容器。声明变量就是创造了一个容器(在内存空间中开辟了一块空间),为变量初始化或赋值就是在往容器里填充/改变内容。

二 变量的声明与使用

2.1 声明变量

(1)声明一个变量

分为两大类:var声明与简短声明

四种具体形式如下

// 1、完整版,与C语言相比, Go语言摒弃了语句必须以分号作为语句结束标记的习惯。
var 变量名 类型 = 初始表达式 

// 2、省略赋值,采用零值,每种类型都有其对应的零值,详见下一章
var 变量名 类型 

// 3、省略类型,依据初始化表达式得到的值自动推导类型
var 变量名 = 初始表达式

// 4、省略var,即简短声明(只能在函数内用)
变量名 := 初始表达式  // 变量的类型根据表达式来自动推导

举例

var name string = "egon"

var name string  // name采用零值为""

var name = "egon"

name:="egon"

(2)声明一组变量

前提:声明的一组变量中每个变量都必须被赋值!!!!!!

// 1、声明一组类型相同的
var a, b, c int = 10,20,30
fmt.Println(a,b,c) // 10 20 30
var x, y, z int // 采用零值,int类型的零值为0
fmt.Println(x,y,z) // 0 0 0

// 2、声明一组类型不同的
var x, y, z = true, 3.1, "egon" // 类型推导出为bool、float64、string

// 3、声明一组类型不同的,注意每行结尾不要加逗号
var (
    m int = 3
    n string
)

// 4、简短声明一组变量
// (1) :=左边至少得有一个新变量,此时,针对老变量就是改值,针对新变量就是声明新的
// (2) 通常变量数量不宜过多,否则影响程序可读性
i, j := 0, 1

思考下述赋值是否正确,并说明原因

// 例1:错误,少赋值了
var a, b, c int = 30 
fmt.Println(a,b,c)

// 例2:错误,少赋值了
x, y := 3
fmt.Println(x,y)

// 例3:错误,重复声明了
x:=1
y:=2
x,y:=111,222
fmt.Println(x,y)

// 例4:正确
x:=1
y:=2
x,y,z:=111,222,333 // 为老变量x,y改值,同时声明一个新变量z
fmt.Println(x,y,z)

// 例5:正确
in, err := os.Open(infile)
out, err := os.Create(outfile)  // err是老变量,同例4

// 例6:错误,简短声明必须至少要声明一个新的变量,下面的代码将不能编译通过
f, err := os.Open(infile)
f, err := os.Create(outfile) // compile error: no new variables

解决方法:第二个简短声明语句改为赋值语法,注意是赋值语法而不是声明语法
f, err = os.Create(outfile) // 注意此时用的是赋值符号"=",而不是变声明语句”:=“

(3)匿名变量

下划线_称之为匿名变量(anonymous variable),接收的值不占用命名空间、不会分配内存、且无法被使用,即它接收的值都相当于被废弃掉了

func main() {
    // 无需声明就可以用,但是声明了也可以,不会报错
    _=1
    _=2
    _=3  

    // 重复声明也没问题
    var _ = 1
    var _ = 2
    var _ = 3

    // 不能使用匿名变量,接收即为废弃
    fmt.Println(_)  // 报错:cannot use _ as value
}

综上,匿名变量通常用于多重赋值时忽略某个值,如下所示

func main() {
    // 这可以让代码非常清晰,基本上屏蔽掉了可能混淆代码阅读者视线的内容
    // 从而大幅降低沟通的复杂度和代码维护的难度。
    var age,_=foo() 
    fmt.Println(age)

    var _,name=foo()
    fmt.Println(name)
}

func foo()(int,string)  {
    return 18,"egon"
}

了解:在Lua等编程语言里,匿名变量也被叫做哑元变量。

2.2 总结声明变量需要注意的其他问题

  • 1、在函数内

    • (1)函数内变量必须先声明、后使用,如下
    package main
    
    import "fmt"
    var x int = 3
    func main() {
        // 此处访问的是main函数内的x
        // 没有遵循函数内变量先声明后使用的原则
        // 所以报错x declared but not used
        fmt.Println(x)  
        var x int = 4
    }
    • (2)函数内声明之后就必须要用,否则无法通过编译,函数外则没有这一限制

    注意:读取变量的值进行打印或运算才叫使用变量,声明与赋值不是引用变量。

    var x int 
    x=3 // 这不算使用x,因为没有读取变量的值
  • 2、匿名变量无需声明,且不能被使用,接收即废弃

  • 3、同一作用域内不能出现重复的声明,匿名变量除外

    var x int 
    x:=3  // 错误:不能重复声明变量
  • 4、var声明与简短声明

    • (1)var可以用于任意位置,即用在函数外也行,但简短声明只能用于函数内部
    • (2)事实上,声明语句var通常的用于”初始值无关紧要,变量稍后会被重新赋值“的场景,所以说,采用零值初始化是var语句的常态
    var 变量名 类型 // 事先声明好类型,用零值完成初始化,相当于做好了准备工作
    • (3)请记住“:=”是一个变量声明语句,而“=‘是一个变量赋值操作;所以,千万不要混淆多个变量的声明和元组的多重赋值,后者是将右边各个的表达式值赋值给左边对应位置的各个变量:
    // 在函数内,简短声明多个变量
    i, j := 111, 222 
    
    // 变量的赋值
    i, j = 333, 444
    i, j = j, i // 交换 i 和 j 的
    
    // 强调::= 是一个变量声明语句,要求等号左边至少有一个新变量
    _ := 666 // 当:=的左边只有一个匿名变量时,会编译错误,因为匿名变量不是新变量

2.3 变量的使用

引用变量/变量值的方式可以是

1、使用变量名

2、使用表达式,比如x[i]、x.f、*p

引入一个例子

var x int = 100

y=:x

左值与右值

 var x int = 100中的x,与y:=x中的x是不一样的

(1) var x int = 100中的x位于赋值符号的左边,称之为左值,代表的是赋值/写操作
会被编译器编译成一个地址,类似:0X3000,所以其左值代表的是内存地址,

(2)、y:=x中的x位于赋值符号的右边,称之为右值,代表的是取值/读操作
会被编译器编译成一个根据地址取值操作,类似:(0X1000),所以右值代表的是根据地址读取内存空间中的内容。

!!!注意!!!
(0X1000)取到的内容,可能是一个值也可能是一个地址,无论是啥,都会将该内容拷贝一个副本来进行后续操作。这句话很重要,如果不理解也没啥关系,先死记硬背下来,你将会在指针那一小节得到详细答案

总结:无论采用何种方式使用变量

当变量的引入方式存在于赋值符号左边时,代表是对变量进行写操作
当变量的引入方式不在赋值符号左边时,,代表是对变量进行读操作
fmt.Println(x) // 针对变量x的读操作
z:=x+200      // 针对变量x的读操作
上一篇
下一篇
Copyright © 2022 Egon的技术星球 egonlin.com 版权所有 帮助IT小伙伴学到真正的技术