变量
变量赋值
- 赋值顺序
- 从左至右赋值
- 如果右侧的表达式计算引用了左侧变量,则创建临时拷贝
- 赋值时,首先计算出所有右值(可能用到左值),然后依次赋值
- 多变量赋值
- 左侧只要有一个新变量就可以使用
:=
声明,其余变量仅仅是赋值- 前提是其余变量的定义位于同一作用域
- 因此如果左侧的局部变量和上层作用域变量同名,则会覆盖上层变量
- 通常出现在全局变量以及for、if等产生括号的情况下
- 左侧只要有一个新变量就可以使用
x := []int{
1,2,3}
i := 0
i, x[i] = 1,2 // set i = 1; x[0] = 2
x[i], i = 2,1 // set x[0] = 2, i = 1
x[i], i = 2, x[i] // set t = x[0], x[0] = 2, i = t = 1
x[0], x[0] = 1,2 // set x[0] = 2
var a int = 1
func f() {
b := 1
a,b := 2,2 // a是新变量,b重新赋值
}
func shadow() (err error) {
x, err := check1() // x是新创建变量,err是被赋值
if err != nil {
return // 正确返回err
}
if y, err := check2(x); err != nil {
// y和if语句中err被创建
return // if语句中的err覆盖外面的err而不是赋值,所以错误的返回nil
} else {
fmt.Println(y)
}
return
}
++
操作费只能作为后缀,且不可赋值a = b++
编译错误
变量可见性
-
当
user
被嵌入Admin
,Admin.Name
是可以导出的- 因为此时内部类型的字段已经提升到了外部类型
-
可以通过
func New(<参数>) <接口类型> {}
声明非导出变量
- 这样和其他人进行函数方法通信的时候,只需约定好接口就可以了,从而隐藏了实现
变量类型
- 常量
- 类型包括:整型,浮点型,复数类型,布尔类型,字符串类型
- 常量的赋值是编译期行为,右值不能出现在运行期才能确定的表达式
- 例如
const Home = os.GetEnv("HOME")
- 例如
uint
类型变量不要相减- 如果
a < b
,则a-b
会变成一个非常大的数 - 显示类型转化时,如果转成指针,单向通道或者函数,应该使用括号,以避免歧义
- 例如
(*int)p
,(<-chan int)(c)
,(func())(f)
- 例如
- 如果
- 变量不支持隐式类型转换
- 例如字符串和数字不可相加,int类型的1,0不可以当做true, false使用
- 类型在再定义:
type newType int
newType
和int
不被视为同一类型- 因为go不支持隐式转换
- 别名:
type newName = int
- newName和int还是同一类型
- 例如
type byte = uint8
,type rune = int32
- 例如
- 主要是为了代码重构而存在的
- newName和int还是同一类型
结构体
- 结构体的字段顺序也是其类型组成部分
- 拥有相同字段但顺序不一样的结构体视为不同类型
- 结构体内存对齐
- struct的字段顺序影响struct的大小
- 具体规则:https://www.flysnow.org/2017/07/02/go-in-action-unsafe-memory-layout.html#struct
引用类型变量初始化
// 切片
var slice []int // nil切片,底层指针为nil,长度为0
slice := []int{
} // 空切片,底层指针存在,长度为0
slice := make([]int, 0) // 同上
slice := a[0:2] // 注意此时slice是一个切片类型,共享底层数组
slice := make([]int, 5, 10) // 声明长度和容量
slice := []int{
1,2,3} // 初始化并赋值
// 字典
var m1 map[string]int // m1 == nil
m2 := make(map[string]int,0) // 空字典, m2 != nil
m3 := map[string]int{
} // 同上
nums := make(map[string]int, 10) // 可以指定初始容量,以提高效率
rate := map[stirng]float64{
"a":4.5,
"bbc":3.0,
} // 初始化并赋值
// channel
ch1 := make(chan int) // 无缓冲通道
ch2 := make(chan int, 0) // 同上
ch3 := make(chan string, 1) // 有缓冲通道
var ch4 chan float64 // ch4 == nil
不可寻址的值
- 不可变的值
- 常量、字符串的索引表达式等
- 临时结果
- 算术操作的结果值、函数或方法的调用表达式、向通道发送元素值或从通道那里接收元素值的接收表达式等
- 不安全的