《Go语言精进之路》第二、三章部分内容学习记录笔记。
1.基本原则
Golang开发中,可遵守简单且一致的命名原则,力求命名精简、易懂和一致。
- package声明
Golang的package声明以小写形式的单个词进行命名:
shopservice、utils、logs、tcc、logconfigs、encoding [good]
不建议以复合词形式来命名:
shop_service、log_configs [bad]
- 变量声明
已存在类型信息时,不要重复类型信息:
users []*User [good]
userList []*User [bad]
使用驼峰形式来声明变量,而不是下划线形式:
var userInfo *User [good]
var user_info *User [bad]
- 常量声明
使用驼峰形式来声明变量,而不是下划线形式:
const (
TaskTypeA = "A" [good]
Task_Type_B = "B" [bad]
)
对于专有名词或特定常量,可使用全大写形式:
const (
SIGABRT = Singnal(0x6) [good]
SIGALRM = Singnal(0xe) [good]
sig_abrt = Singnal(0x6) [bad]
)
- 接口声明
对于接口类型优先以单个单词命名。对于拥有唯一方法(method)或通过多个拥有唯一方法的接口组合而成的接口,Go语言的惯例是用“方法名+er”命名。
type Writer interface { [good]
}
type Write interface { [bad]
}
- for循环标识声明
存在上下文说明的地方,尽量简单明了,避免出现大段已知含义命名,避免冗余:
for i := 0, i < len(s); i++ { [good]
v := s[i]
...
}
for index := 0, index < len(s); index++ { [bad]
value := s[index]
...
}
2.变量声明
2.1.包级别变量
- 包级别变量声明
包级变量只能使用带有var关键字的变量声明形式,并推荐声明时将含义和作用相近的变量放在一个var块中,类型建议后移:
var ( [good]
a = int32(1)
f = float32(3.14)
)
var ( [bad]
a int32 = 1
f float32 = 3.14
)
- 延迟声明
对于声明时并不立即初始化的包级变量,可以直接声明:
var a int32
var f float32
- 使用就近原则
不是所有的包级变量都一定需要放置在文件头中,可以在第一次使用的函数上方放置:
var ErrNoUserInfo = errors.New("用户信息不存在")
func GetUserInfo(name string) (*User, error) {
...
return nil, ErrNoUserInfo
}
2.2.函数级别变量
- 函数级别变量声明
通常对于延迟初始化的局部变量,可以使用var来进行前置声明:
func GetUserInfo(name string)(*User, error) {
// 前置声明
var user *User
if user, err := getUserDB(name); err != nil {
return nil, err
}
return user, nil
}
- 对于声明且初始化的局部变量,采用短式声明:
[good]
taskType := int32(1)
s := []byte("hlelo")
[bad]
var taskType int32 = 1
var s []byte = []byte("hello")
- 对于分支控制变量或for循环中变量,采用短式声明:
[good]
func Do(userName string) (*User, error){
var u User
if u, ok := userMap[userName]; !ok {
return nil, ErrNoUser
}
for _, s := range u.Shops {
handleShop(s)
...
}
}
[bad]
func Do(userName string) (*User, error){
var user User
if user, existUser := userMap[userName]; !existUser {
return nil, ErrNoUser
}
for _, userShop := range user.Shops {
handleShop(userShop)
...
}
}
3.常量声明
- 常量声明与包级别变量声明类似,相同类型的常量可聚合在一个const块中,默认类型不指定(如a是int类型),特殊类型后置指定(f是float64类型)
const ( [good]
a = 1
f = float64(3.14)
)
const ( [bad]
a int32 = 1
f float64 = 3.14
)
- 对于存在递增声明的常量,可以采用iota语法糖简化,避免手写冗余的递增值
[good]
const (
_ = iota // 0
A
B
C
)
[bad]
const (
A = 1
B = 2
C = 3
)
4.零值可用
- 切片append零值可用
var list []int // 该切片声明为零值
list = append(list, 1) // 依然生效,会自动初始化list
- mutex零值可用
var mu sync.Mutex // 该mutex声明为零值
mu.Lock()
mu.Unlock()
- 结构体零值可用
type Person struct {
Name string
Age int
Child *Person
}
func main() {
var p Person // 声明结构体后,自动为其内部各字段赋零值
p.Age = 1
p.Name = "test"
p.Child = &Person{}
}
- 零值指针调用方法可用
func (p *Person) GetPersonName() string {
if p == nil {
return "<nil>"
}
return p.Name
}
func main() {
var p *Person // 声明零值指针
name := p.GetPersonName() // 零值指针调用方法
fmt.Println(name) // 输出<nil>,表明零值指针调用方法可行
}