• Go学习笔记-Effective Go


    Go特性,编程惯例(命名,格式,程序构造)

     1.代码格式

    gofmt(包级而不是源码级),代码格式化。

    所有标准包中的Go代码都用gofmt格式化了。

    使用Tab间隔(gofmt自动设置),而不是空格。

    vscode 集成了gofmt,go文件保存时会自动格式化。

    2.注释

    块注释:/**/(包注释)          行注释//

    godoc产生代码文档,处理Go源码文件,提取包的内容文档。,没有新行干预,和声明一起被提取作为解释文本给服务器。这些注释的风格决定godoc产生的文档的质量。

    每个包都应该有一个包注释,包声明语句前的块注释。对于多文件包,包注释只需要在一个文件中呈现。包注释应该将介绍包并提供包的相关信息。它将出现在godoc的首页。

    /*
    Package regexp implements a simple library for regular expressions.
    
    The syntax of the regular expressions accepted is:
    
        regexp:
            concatenation { '|' concatenation }
        concatenation:
            { closure }
        closure:
            term [ '*' | '+' | '?' ]
        term:
            '^'
            '$'
            '.'
            character
            '[' [ '^' ] character-ranges ']'
            '(' regexp ')'
    */
    package regexp

    如果包很简单,行注释。

    注释不需要额外的格式例如*。godoc的输出可能不会已定宽字体显示,因此不能依赖空格。注释是不间断的普通文本。

    依赖上下文,godoc也许都不会重新格式化注释,确保注释直观:使用正确的拼写,准确,语句结构,收起长的行等。

    程序中每个导出名(大写开头)应该有一个文档注释。完整语句,第一个语句应该是一句话概括,以被声明的名开头。

    // Compile parses a regular expression and returns, if successful,
    // a Regexp that can be used to match against text.
    func Compile(str string) (*Regexp, error) {}

    如果每个文档注释以它描述的名称开头,可以使用go工具的doc子命令并通过grep运行输出。例如,记不住Compile但寻找正则表达式的转换函数,可以运行如下指令

    go doc -all regexp |grep -i parse

    如果所有文档注释以This function开头,grep不能帮助你记住名字。但因为包的文档注释以名字开头,调用上面的命令有如下结果:

    $ go doc -all regexp | grep -i parse
        Compile parses a regular expression and returns, if successful, a Regexp
        MustCompile is like Compile but panics if the expression cannot be parsed.
        parsed. It simplifies safe initialization of global variables holding
    $

    Go的声明语句允许声明组合。一个文档注释可以引入一组相关的常量或变量。由于整个声明被呈现,注释通常都是草率的。

    // Error codes returned by failures to parse an expression.
    var (
        ErrInternal      = errors.New("regexp: internal error")
        ErrUnmatchedLpar = errors.New("regexp: unmatched '('")
        ErrUnmatchedRpar = errors.New("regexp: unmatched ')'")
        ...
    )

    组合也可以表明项之间的关系,例如一系列变量由一个互斥锁保护的事实。

    var (
        countLock   sync.Mutex
        inputCount  uint32
        outputCount uint32
        errorCount  uint32
    )

    3.名称

    命名有语义影响:包外是否可见取决于首字母是否大写。

    包名

    当包被导入后,报名成为包内容的访问器。例:bytes.Buffer

    import "bytes"

    包命名应该短,简洁,有意义。按照惯例,包名是小写字母,一个词,不需要下划线或混合。不必担心包命名冲突,导入时可以选择局部的不同名来使用。

    另一个惯例:包名基于它的源目录。在src/encoding/base64的包以"encoding/base64"被导入,但是以base64命名,而不是encoding_base64 或encodingBase64。

    长名称不能自动使代码可读性更强。有用的文档注释相比起额外的长命名会更有价值。

    属性

    Go不自动支持获取和设置。提供获取或设置没任何问题,通常需要这么做,但是将Get放入获取函数名称内并无必要。如果有一个owner字段(小写,非导出),owner应该通过Owner获取,而不是GetOwner.

    如果需要设置方法,命名SetOwner。

    接口名称

     按照惯例,一个方法的接口以方法名加上er后缀(或类似修改构建一个代理名词)来命名,如Reader,Writer,Formatter。

    这样的命名很多,Read,Write,Close等有规定的签名和含义。为了避免混淆,不要用上述名称来给你的方法命名除非它有相同签名和含义。相反地,如果你的类型实现与现有类型相同含义的方法,给它相同的命名和签名方式。

    将字符串转换方法命名为String,而不是ToString。

    混合

    使用MixedCaps或mixedCaps来写多单词名称而不是下划线。

    4.分号

     词义解释器自动插入分号,可以概括为:如果新行的上一行是可能结束一个语句的标记,在上一行添加分号

    这导致if,for,switch或select的{不能换行写;不然if i<f()后面自动添加分号,不会执行条件判断。

    5.控制结构

      go的控制结构和C的显示,但没有do或while循环,只有for。if,switch,for接受可选初始化语句。

    语法也有些不同:提交件判断没有括号,主体必须用{}包裹。

    If

    if err := file.Chmod(0664); err != nil {
        log.Print(err)
        return err
    }

    重声明和重赋值

    f, err := os.Open(name)
    if err != nil {
        return err
    }
    d, err := f.Stat()
    if err != nil {
        f.Close()
        return err
    }
    codeUsing(f, d)

    os.Open->err 被f.Start()->err覆盖。看起来,是err被声明了两次(通过:=),合法,第二次只是被重赋值。

    通过:=声明已被声明的变量v在以下情况会出现:

    1.该声明与已有声明在同一个作用域

    2.相关的值在初始化时赋值给v,至少有另一个变量在这个声明中创建

    这个特性非常实用,在长的if-else链中只使用一个err值。

    For

    Go语言中的for循环统一了for,while不包含(do-while)。共有三种形式:

    // Like a C for
    for init; condition; post { }
    
    // Like a C while
    for condition { }
    
    // Like a C for(;;)死循环
    for { }

    下划线标志 

    遍历数组,切片,字符串,map, 使用range

    for key, value := range oldMap {
        newMap[key] = value
    }
    for _, value := range oldMap {
        newMap[key] = value
    }
     

    对于字符串,range做的更多,通过转换UTF-8划分单个Unicode编码点。错误的编码使用一个字节产生替换的rune U+FFFD(内建类型rune是go 术语-单个Unicode编码点。)

     Switch

    Go的switch比C的更常用。表达式不需要为常量或者整数,cases从上到下匹配直到找到匹配,不需要显示break,匹配上就会break,不会匹配其他cases。可以用来写if-else-if-else链,相当于do{break;}while(false)。break+标签跳出循环(区别于跳出switch)

    Loop:
        for n := 0; n < len(src); n += size {
            switch {
            case src[n] < sizeOne:
                if validateOnly {
                    break
                }
                size = 1
                update(src[n])
    
            case src[n] < sizeTwo:
                if n+1 >= len(src) {
                    err = errShortInput
                    break Loop
                }
                if validateOnly {
                    break
                }
                size = 2
                update(src[n] + src[n+1]<<shift)
            }
        }

    类型switch

    switch可以用于识别接口变量的动态类型。type switch很实用类型诊断语法(关键字type)。如果switch在表达式中声明了明亮,变量在每个字句中都有相应的类型。

    var t interface{}
    t = functionOfSomeType()
    switch t := t.(type) {
    default:
        fmt.Printf("unexpected type %T
    ", t)     // %T prints whatever type t has
    case bool:
        fmt.Printf("boolean %t
    ", t)             // t has type bool
    case int:
        fmt.Printf("integer %d
    ", t)             // t has type int
    case *bool:
        fmt.Printf("pointer to boolean %t
    ", *t) // t has type *bool
    case *int:
        fmt.Printf("pointer to integer %d
    ", *t) // t has type *int
    }

    6.函数

    多个返回值

    Go的特性之一就是函数或方法可以返回多个值。

    在C语言中,写错误通过负值标记。在go语言中,Write可以返回数值和error(字符串描述信息)。

    命名返回参数

    Defer

    7.数据

     

  • 相关阅读:
    产品需求说明书PRD模版
    会编程的 AI + 会修 Bug 的 AI,等于什么 ?
    会编程的 AI + 会修 Bug 的 AI,等于什么 ?
    会编程的 AI + 会修 Bug 的 AI,等于什么 ?
    luogu P1164 小A点菜
    luogu P1347 排序
    luogu P1195 口袋的天空
    luogu P1182 数列分段Section II
    luogu P1332 血色先锋队
    luogu P1983 车站分级
  • 原文地址:https://www.cnblogs.com/mbaymax/p/15030596.html
Copyright © 2020-2023  润新知