Go学习笔记-Effective Go

摘要:
vscode集成了gofmt,go文件保存时会自动格式化。//Compileparsesaregularexpressionandreturns,ifsuccessful,//aRegexpthatcanbeusedtomatchagainsttext.funcCompile{}如果每个文档注释以它描述的名称开头,可以使用go工具的doc子命令并通过grep运行输出。但因为包的文档注释以名字开头,调用上面的命令有如下结果:$godoc-allregexp|grep-iparseCompileparsesaregularexpressionandreturns,ifsuccessful,aRegexpMustCompileislikeCompilebutpanicsiftheexpressioncannotbeparsed.parsed.Itsimplifiessafeinitializationofglobalvariablesholding$Go的声明语句允许声明组合。在src/encoding/base64的包以"encoding/base64"被导入,但是以base64命名,而不是encoding_base64或encodingBase64。将字符串转换方法命名为String,而不是ToString。ForGo语言中的for循环统一了for,while不包含。

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, ifsuccessful, a Regexp
    MustCompile is like Compile but panics ifthe expression cannot be parsed.
    parsed. It simplifies safe initialization of globalvariables 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)
    returnerr
}

重声明和重赋值

f, err :=os.Open(name)
if err !=nil {
    returnerr
}
d, err :=f.Stat()
if err !=nil {
    f.Close()
    returnerr
}
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
forinit; condition; post { }

//Like a C while
forcondition { }

//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:
            ifvalidateOnly {
                break}
            size = 1update(src[n])

        case src[n] <sizeTwo:
            if n+1 >=len(src) {
                err =errShortInput
                breakLoop
            }
            ifvalidateOnly {
                break}
            size = 2update(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.数据

免责声明:文章转载自《Go学习笔记-Effective Go》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇socket网络编程(三)——select多路复用问题oracle 报错 :ORA-04052、 ORA-00604、 ORA-03106、 ORA-02063下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章