变量常量
# 变量
Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。
# 变量声明
- 第一种,指定变量类型,如果没有初始化,则变量默认为零值。通用的变量声明格式: 式:
var a int = 10
这个变量声明分为四个部分:
- var是修饰变量声明的关键字;
- a为变量名;
- int为该变量的类型;
- 10是变量的初值。
第二种,根据值自行判定变量类型。
第三种,如果变量已经使用 var 声明过了,再使用 := 声明变量,就产生编译错误,格式:
v_name := value
# 多变量声明
多变量声明是针对类型相同多个变量, 非全局变量
var vname1, vname2, vname3 type
vname1, vname2, vname3 = v1, v2, v3
var vname1, vname2, vname3 = v1, v2, v3 // 和 python 很像,不需要显示声明类型,自动推断
vname1, vname2, vname3 := v1, v2, v3 // 出现在 := 左侧的变量不应该是已经被声明过的,否则会导致编译错误
// 这种因式分解关键字的写法一般用于声明全局变量
var (
vname1 v_type1
vname2 v_type2
)
# 变量注意事项
变量所绑定的内存区域是要有一个明 确的边界的。
也就是说,通过这样一个变量,我们究竟可以操作4个字节内存还是8个字节内 存,又或是256个字节内存,编程语言的编译器或解释器需要明确地知道。声明聚类与就近原则
就近原则,也就是说 我们尽可能在靠近第一次使用变量的位置声明这个变量。就近原则实际上也是对变量的作用 域最小化的一种实现手段,如标准库http包中的代码就是这样:
// $GOROOT/src/net/http/request.go
var ErrNoCookie = errors.New("http: named cookie not present")
func (r *Request) Cookie(name string) (*Cookie, error) {
for _, c := range readCookies(r.Header, name) {
return c, nil
}
return nil, ErrNoCookie
}
# 变量分类
通常来说,Go语言的变量可以分为两类:
- 一类称为包级变量(package varible),也就是在 包级别可见的变量。如果是导出变量(大写字母开头),那么这个包级变量也可以被视为全 局变量;
- 另一类则是局部变量(local varible),也就是Go函数或方法体内声明的变量,仅在 函数或方法体内可见。
# 包级变量的声明形式
包级变量只能使用带有var关键字的变量声明形式,不能使用短变量声 明形式,但在形式细节上可以有一定灵活度。
- 第一类:声明并同时显式初始化
var varName = initExpression
尽量保证声明一致性,,这 样能统一接受默认类型和显式指定类型这两种声明形式。
var (
a = 13
b = int32(17)
f = float32(3.14)
)
- 第二类:声明但延迟初始化 如:var a int32, 虽然没有显式初始化,Go语言也会让这些变量拥有初始的“零值”。如果是自定义的类型,尽量保证它的零值是可用的。 还有一个注意事项,就是声明聚类与就近原则。
# 局部变量的声明形式
和包级变量相比,局部变量又 多了一种短变量声明形式,这是局部变量特有的一种变量声明形式,也是局部变量采用最多 的一种声明形式。
- 第一类:对于延迟初始化的局部变量声明,我们采用通用的变量声明形式
- 第二类:对于声明且显式初始化的局部变量,建议使用短变量声明形式 对于不接受默认类型的变量,我们依然可以使用短变量声明形式,只是在":="右侧要做一个显 式转型,以保持声明的一致性:
a := int32(17)
f := float32(3.14)
s := []byte("hello, gopher!")
并且,尽量在分支控制时使用短变量声明形式;
但是如果你在声明局部变量时遇到了适合聚类的应用场 景,你也应该毫不犹豫地使用var声明块来声明多于一个的局部变量,如标准库net包中resolveAddrList方法:
// $GOROOT/src/net/dial.go
func (r *Resolver) resolveAddrList(ctx context.Context, op, network,
addr string, hint Addr) (addrList, error) {
... ...
var (
tcp *TCPAddr
udp *UDPAddr
ip *IPAddr
wildcard bool
)
... ...
}
# 常量
常量是一个简单值的标识符,在程序运行时,不会被修改的量。
常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
常量的定义格式:
const identifier [type] = value
// 你可以省略类型说明符 [type],因为编译器可以根据变量的值来推断其类型。
//显式类型定义:
const b string = "abc"
//隐式类型定义:
const b = "abc"
//多个相同类型的声明可以简写为:
const c_name1, c_name2 = value1, value2
# 零值
Go规范定义的内置原生类型的默认 值(即零值)
数据类型 | 默认值 |
---|---|
int | 0 |
float | 0.00000 |
string | "" |
结构体 | 根据结构体内部的基础数据类型进行初始化赋值 |
数组(切片) | 空数组 |
指针 | nil |
# 代码块与作用域
变量遮蔽是Go开发人员在日常开发工作中最容易犯的编码错误之一。 要想彻底保证不出现变量遮蔽问题,我们需要深入了解代码块与作用域这两个概 念以及其背后的规则。
# 避免变量遮蔽的原则
一个变量的作用域起始于其声明所在的代码块,并且可以一直扩展 到嵌入到该代码块中的所有内层代码块,而正是这样的作用域规则,成为了滋生“变量遮蔽 问题”的土壤
- 显式代码块
由两个肉眼可见的且配对的大括号包裹起来 的,我们称这样的代码块为显式代码块(Explicit Blocks) - 隐式代码块
顾名思义,隐式代码块(Implicit Block)没有显式代码块那样的肉眼可见的配对大括号包裹,我们无法通过大括号来识别隐式代码块。