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


    在这里插入图片描述

    《Go语言精进之路》第二、三章部分内容学习记录笔记。

    1.基本原则

    Golang开发中,可遵守简单且一致的命名原则,力求命名精简、易懂和一致。

    • package声明
      Golang的package声明以小写形式的单个词进行命名:
    shopservice、utils、logs、tcc、logconfigs、encoding    [good]
    
    • 1

    不建议以复合词形式来命名:

    shop_service、log_configs    [bad]
    
    • 1
    • 变量声明
      已存在类型信息时,不要重复类型信息:
    users []*User    [good]
    userList []*User     [bad]
    
    • 1
    • 2

    使用驼峰形式来声明变量,而不是下划线形式:

    var userInfo *User    [good]
    var user_info *User    [bad]
    
    • 1
    • 2
    • 常量声明
      使用驼峰形式来声明变量,而不是下划线形式:
    const (
        TaskTypeA = "A"    [good]
        Task_Type_B = "B"    [bad]
    )
    
    • 1
    • 2
    • 3
    • 4

    对于专有名词或特定常量,可使用全大写形式:

    const (
        SIGABRT = Singnal(0x6)    [good]
        SIGALRM = Singnal(0xe)    [good]
        sig_abrt = Singnal(0x6)    [bad]
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 接口声明
      对于接口类型优先以单个单词命名。对于拥有唯一方法(method)或通过多个拥有唯一方法的接口组合而成的接口,Go语言的惯例是用“方法名+er”命名。
    type Writer interface {    [good]
    }
    
    type Write interface {    [bad]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • for循环标识声明
      存在上下文说明的地方,尽量简单明了,避免出现大段已知含义命名,避免冗余:
    for i := 0, i < len(s); i++ {    [good]
        v := s[i]
        ...
    }
    
    for index := 0, index < len(s); index++ {    [bad]
        value := s[index]
        ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.变量声明

    2.1.包级别变量

    • 包级别变量声明
      包级变量只能使用带有var关键字的变量声明形式,并推荐声明时将含义和作用相近的变量放在一个var块中,类型建议后移:
    var (    [good]
        a = int32(1)
        f = float32(3.14)
    )
    
    var (    [bad]
        a int32 = 1
        f float32 = 3.14
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 延迟声明
      对于声明时并不立即初始化的包级变量,可以直接声明:
    var a int32
    var f float32
    
    • 1
    • 2
    • 使用就近原则
      不是所有的包级变量都一定需要放置在文件头中,可以在第一次使用的函数上方放置:
    var ErrNoUserInfo = errors.New("用户信息不存在")
    
    func GetUserInfo(name string) (*User, error) {
        ...
        return nil, ErrNoUserInfo
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 对于声明且初始化的局部变量,采用短式声明:
    [good]
    taskType := int32(1)
    s := []byte("hlelo")
    
    [bad]
    var taskType int32 = 1
    var s []byte = []byte("hello")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 对于分支控制变量或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)
           ...
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    3.常量声明

    • 常量声明与包级别变量声明类似,相同类型的常量可聚合在一个const块中,默认类型不指定(如a是int类型),特殊类型后置指定(f是float64类型)
    const (    [good]
        a = 1
        f = float64(3.14)
    )
    
    const (    [bad]
        a int32 = 1
        f float64 = 3.14
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 对于存在递增声明的常量,可以采用iota语法糖简化,避免手写冗余的递增值
    [good]
    const (
        _ = iota // 0
        A
        B
        C
    )
    
    [bad]
    const (
        A = 1
        B = 2
        C = 3
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.零值可用

    • 切片append零值可用
    var list []int // 该切片声明为零值
    list = append(list, 1) // 依然生效,会自动初始化list
    
    • 1
    • 2
    • mutex零值可用
    var mu sync.Mutex // 该mutex声明为零值
    mu.Lock()
    mu.Unlock()
    
    • 1
    • 2
    • 3
    • 结构体零值可用
    type Person struct {
       Name string
       Age int
       Child *Person
    }
    
    func main() {
       var p Person // 声明结构体后,自动为其内部各字段赋零值
       p.Age = 1
       p.Name = "test"
       p.Child = &Person{}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 零值指针调用方法可用
    func (p *Person) GetPersonName() string {
       if p == nil {
          return ""
       }
       return p.Name
    }
    
    func main() {
       var p *Person             // 声明零值指针
       name := p.GetPersonName() // 零值指针调用方法
       fmt.Println(name)         // 输出,表明零值指针调用方法可行
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    Java练习题第八期:求数组中超过数组长度一半的数字
    springboot+vue基于Spark的共享单车数据存储系统的设计与实现【内含源码+文档+部署教程】
    c#找到是哪个函数调用当前函数
    数据要素价值:在数字时代的血脉中流淌
    HttpServletRequest相关
    金融行业需要什么样的低代码平台?
    iOS ijkplayer 硬解H265(hevc)4k视频问题解决
    《对比Excel,轻松学习Python数据分析》读书笔记------数据分组与数据透视表
    Vue动态路由配置
    GcExcel与 Apache POI 在功能和性能上的对比测试
  • 原文地址:https://blog.csdn.net/pbrlovejava/article/details/128171116