Golang开发习惯:变量、常量声明&使用惯例

在这里插入图片描述

《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>,表明零值指针调用方法可行
}

猜你喜欢

转载自blog.csdn.net/pbrlovejava/article/details/128171116