变量:
变量是在程序运行过程中,其值可以发生改变的量

变量名:

因为内存分配发生在运行期,所以在编码阶段我们用一个易于阅读的名字来表示这段内存,称为变量名。 实际上编译后的机器码从不使用变量名,而是通过内存地址来访问目标数据。

变量语法的注意事项:

右边内存空间写左边数据值读

变量的定义:

var
	x int  		// 定义x	没初始化	默认值0y = 1  		// 定义y	有初始化	数据类型intvar z bool  // 定义z	没初始化	默认值为false

可以一次性定义多个变量:

	var x, y int           // 多个变量相同数据类型var n, m = 100, "呵呵" // 多个变量不同数据类型

多个变量以组的方式定义:

	var (x, y intn, m = 100, "呵呵")

自动推导类型:

:是局部变量
	num := 1x, y, z := 1, 2, "嘻嘻"fmt.Println(num, x, y, z)

自动推导类型不一定是重新定义变量,也可能是重新赋值操作

func test() {x := 100println(&x)x, y := 200, "abc" //注意,x为赋值操作	仅有y是新变量定义println(&x, x)println(y)
}

打印结果:

0x14000096f60
0x14000096f60 200
abc

自动推导类型定义的不是全局变量,是局部变量

var num = 100func test() {fmt.Println(&num,num)num := "我被重新赋值了,我和外面的num不一样"fmt.Println(&num,num) 
}

打印结果:

0x1042b4288 	100
0x14000110210 	看看我是不是全局变量

定义变量必须是同一作用域内,且是新的变量

func test2() {x := 1 // 0x14000120008fmt.Println(&x)x := 2 // 报错:等号左边不是新的变量{x := 3          // 不同作用域都是新的变量fmt.Println(&x) // 0x1400001a098}
}
err
func test5() {f, err := os.Open("/Users/itzhuzhu/Desktop/goCode/go_basics")if err != nil {fmt.Println("os.Open err:", err)return}fmt.Println(&err)buf := make([]byte, 1024)n, err := f.Read(buf)if err != nil {fmt.Println("os.Open err:", err)return}fmt.Println(n)fmt.Println(&err)
}

打印结果:

0x14000110210
26
0x14000110210

多变量赋值:

在进行多变量赋值操作时,首先计算出所有右值,然后依次完成赋值操作,但必须保证左右值的数据类型相同

func test6() {x, y := 1, 2	// x:1  y:2x, y = y+3, x+2 // 先计算出右值y+3、x+2,然后再对x、y变量赋值。fmt.Println(y)
}

局部变量&全局变量:
  • 定义函数内部的变量称为局部变量,局部变量的作用域在函数的内部
  • 定义函数外部的变量称为全局变量,全局变量的是任何函数都可以使用
  • 如果全局变量和局部变量的名字相同,在函数内局部变量的优先级大于全局变量,采用就近原则
var a = 3
var b int = 2
var c := 5 // 自动推导类型不能被函数使用,只能通过varfunc variate() {var d = 4fmt.Println(a, b, d)
}
命名规则:

优先选用有实际含义,易于阅读和理解的字母、单词或组合对变量、常量、函数、 自定义类型进行命名。

名字首字母大小写决定了其作用域
	var c int                 // c代替countfor i := 0; i < 10; i++ { // i代替indexc++}fmt.Println(c)
忽略占位符:
忽略占位符_

空标识符可用来临时规避编译器对未使用变量和导入包的错误检查,但它是预置成员,不能重新定义

import ("fmt"_"os"	// 对于还没用到且不想删除的可以加上占位符,避免编译报错
)
	_, err = conn.Write([]byte(fileName))	// _:表示忽略占位符if err != nil {fmt.Println("conn.Write err:", err)return
}
常量:
常量是在程序运行过程中,其值不可以发生改变的量。const
// 当常量比较多的时候可以使用常量块来表示,比较简洁
const (USERNAME = "itzhuzhu"AGE      = 24ADDRESS  = "广州"
)// 也可以多重赋值
const GENDER, HOBBY = "男", "黑丝"func main() {const USERNAME string = "itzhuzhu2"fmt.Println(USERNAME, AGE, ADDRESS) // 就近原则打印的是itzhuzhu2
}

定义常量不使用不会编译错误,不同作用域也可以定义相同常量

func test8() {const x = 123fmt.Println("我是外面的:", x)const y = 1.23 //	未使用不会引发编译错误{const x = 321 //	不同作用域定义同名变量fmt.Println("我是里面的:", x)}
}

如果显式指定数据类型,必须确保常量左右值类型一致,需要时可做显式转换。右值不能超出常量类型取值范围,否则会引发溢出错误

func test09() {const (x, y int = 99, -999b        = byte(x)  // 如果x没有显式类型定义,那么无需转换n        = uint8(y) // 报错:无法将类型 'int' 的表达式转换为类型 'uint8')
}

常量值也可以是某些编译器能直接计算结果的表达式,如unsafe.Sizeof、len、cap等

func test10() {const (ptrSize = unsafe.Sizeof(uintptr(0))strSize = len("hello, world!"))fmt.Println(ptrSize)fmt.Println(strSize)
}

在常量组中如不指定类型和初始化值,则与上一行非空常量右值(或表达式文本)相同。

func test11() {const (x uint16 = 120y        // 与上一行x类型、右值相同s = "abc"z // 与s类型、右值相同)fmt.Printf("%T, %v\n", y, y) // 输出类型和值fmt.Printf("%T, %v\n", z, z)
}

打印结果:

uint16, 120
string, abc

显示常量和隐式定义常量区别:

const x = 100     // 隐式无常量类型
const y byte = x  // 相当于const y byte = 100
const a int = 100 // 显式指定常量类型,编译器会做强类型検查
const b byte = a  // 错误:cannot use a (type int) as type byte in const initializer
变量和常量的区别:

常量除不可以再次赋值外,和变量究竟有什么不同?

常量不会分配存储空间,无需像变量那样通过内存寻址来取值,因此无法获取地址。
常量值不能再次改变,变量可以

var x = 0x100const y = 0x200func main() {println(&x, x)println(&y, y) // 报错: cannot take the address of y
}
关键字:

Go中有25个关键字,虽不是主流语言中最少的,但也体现了Go语法规则的简洁性。关键字不能用作常量、变量、有数名以及结构字段等标识符。

breakdefaultfuncinterfaceselect
casedefergomapstruct
chanelsegotopackageswitch
constfallthroughifrangetype
continueforimportreturnvar
初始化:

对复合类型(array、slice、struct、map)变量初始化时,有一些语法限制

  • 初始化表达式必须有类型标签
  • 左大括号必须在类型尾部,不能另起一行
  • 多个成员初始值以逗号分隔
  • 允许多行,但每行必须以逗号或右大括号结束
func main () {d := data{ 		// 语法错误:unexpected semicolon or newline (左大括号不能另起一行)1,"abc",}d := data{1,"abc" // //语法错误:need trailing comma before newline (须以逗号或右大括号结束)}
}