package main import ( "fmt" ) func get() { return 1, 2 } func main() { x, y := get() fmt.Println(x) }考点:定义未使用的局部变量和使用匿名变量。
package main // 堆代码 duidaima.com import ( "fmt" ) var ( x = 1 y := 10 ) func main() { fmt.Println(x) }考点:简短模式只能定义局部变量
package main import ( "fmt" ) var i int, s string = 1, "3" func main() { fmt.Println(i, s) }考点:var 定义多个变量
package main import ( "fmt" ) var p *int func foo() (*int, error) { var i int = 5 return &i, nil } func bar() { // 使用 p fmt.Println(*p) } func main() { p, err := foo() if err != nil { fmt.Println(err) return } bar() fmt.Println(*p) }考点:变量的作用域问题
package main import ( "fmt" ) func main() { x := 1 fmt.Println(&x) if x, y := 3, 4; true { x = x + y fmt.Println(&x) } x , y := 5, 6 x = x + y fmt.Println(&x) }考点:局部变量的作用域与简单模式的退化赋值。
变量名称 变量类型 变量值 var varName typeName [= Value]var 是 Go 提供的用于定义变量的关键词,变量的定义语句可出现在函数和包级别中。语句中核心是三个部分,分别是变量的名称、类型和值。与 C/C++ 不同,Go 的变量类型是在变量名称之后。
var i int var 除了定义单个变量,还可以一次定义多个变量。 // 相同类型简写 var i, j int // 定义不同类型变量 var ( i int s string )
var i int = 1 var f float64 = 1.1 var s string = "string"变量值的可选范围由变量类型决定。Go 是静态语言,变量类型是不可修改的。
var i int var s string如果变量定义时,没有指定初始值,将自动初始化为相应的零值(不同类型,零值不同),避免类似 C/C++ 中不可预测的行为。在 windows 上的 “烫烫烫” 的梗,就是和变量未初始化有关。
聚合类型(数组、结构体):每个元素或字段都为对应类型的零值;
var i = 1 // 同时定义初始化两个不同类型变量 var f, s = 1.1, "string"
i := 1变量类型由编译器根据初始化值自动推导。要注意的是,函数外的每个语句都必须以关键字开始(var, func 等),简短模式不能在函数外使用。简短模式下,如果语句左边有多个变量,其中包含已定义变量,且必须是位于当前的作用域,则已定义变量会转化为赋值行为。
var x = 1 fmt.Println(&x, x) x, y := 10, 20 fmt.Println(&x, x)运行代码将会发现,x 的值修改了,但地址并未改变。
x, y := 10, 20 x, y = x+10, y+20这种语法在简化写法的同时,还有一个比较有用的点,变量交换。
t := x x = y y = t引入一个临时变量实现交换。除此之外,还有两种比较常见的交换算法,不引入临时变量。
x = x + y y = x - y x = x - y或者
a = a^b b = b^a a = a^b有了多变量同时赋值的特性之后,如下的写法即可完成交换。
x, y = y, x
func row() (string, int) { return "poloxue", 18 }现在 main 函数将打印第一个返回值,第二个返回值不会使用。
func main() { name, age := row() fmt.Println(name) }编译无法通过,提示存在未使用的变量。这时,可以使用 Go 中提供的匿名变量 _ 接收无用的返回值。
name, _ := row()匿名变量有什么特点?匿名变量可以多次使用,不占用内存空间,解决未使用变量的报错问题。
package main // 全局变量 var i = 1 func printI() { // 局部变量覆盖全局变量 i := 10 fmt.Println(i) } func main() { fmt.Println(i) printI() }局部变量有几种情况,分别是函数的参数与返回值,函数体内部定义变量,函数内部语法块等。
func main() { s := "局部变量" { s := "语法块内部变量" fmt.Println(s) } fmt.Println(s) }变量作用域是一个很坑的话题,Go 中每个语法块,如 func、if、for、select、switch 等,都有一个隐式的作用域。基于它,出现了很多坑死人不偿命的面试题。
func get() int { return 1 } func main() { if x := get(); x == 0 { fmt.Println(x) } else { fmt.Println(x) } }else 中也可以使用 x 变量,if 之上有个隐式作用域。作用域这块还有很多坑,比如与 defer 结合就会产生更多叹为观止(惨绝人寰)的现象。