[翻译] effective go 之 Names Semicolons

pengfei_xue · · 3362 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。


Names are as important in Go as in any other language. In some cases they even have semantic effect: for instance, the visibility of a name outside a package is determined by whether its first character is upper case. It's therefore worth spending a little time talking about naming conventions in Go programs.

命名在所有语言中都很重要 有些情况下 名字有语义上的作用 比如 一个包中的名字的首字母大小写 可以决定这个名字是否可以被导出 

Package names

When a package is imported, the package name becomes an accessor for the contents. After

当包被导入后 包名成了访问它内部命名空间的一个接口

import "bytes"

the importing package can talk about bytes.Buffer. It's helpful if everyone using the package can use the same name to refer to its contents, which implies that the package name should be good: short, concise, evocative. By convention, packages are given lower case, single-word names; there should be no need for underscores or mixedCaps. Err on the side of brevity, since everyone using your package will be typing that name. And don't worry about collisions a priori. The package name is only the default name for imports; it need not be unique across all source code, and in the rare case of a collision the importing package can choose a different name to use locally. In any case, confusion is rare because the file name in the import determines just which package is being used.

上述代码中 bytes被导入后 我们可以直接使用bytes.Buffer 假如每个使用包的人 可以通过同样的名字引用到包中的内容 那将非常给力 这也意味着包的名字需要精简 富有含义 习惯上包名是小写的单个单词 通常不需要使用下划线或者骆驼式来给包起名 不必担心包名有冲突 包名只是在导入时使用的默认名字 它不需要在所有的代码中独一无二 如果出现名字冲突 可以起一个本地的不同的名字 类似python中的import xxx as yyy 

Another convention is that the package name is the base name of its source directory; the package in src/pkg/encoding/base64 is imported as "encoding/base64" but has name base64, not encoding_base64 and not encodingBase64.

另外一个习惯是 包名是源代码结构里的目录名字 包src/pkg/encoding/base64 可以通过"encoding/base64"导入 而不是 encoding_base64 或者 encodingBase64

The importer of a package will use the name to refer to its contents (the import . notation is intended mostly for tests and other unusual situations and should be avoided unless necessary), so exported names in the package can use that fact to avoid stutter. For instance, the buffered reader type in the bufio package is called Reader, notBufReader, because users see it as bufio.Reader, which is a clear, concise name. Moreover, because imported entities are always addressed with their package name,bufio.Reader does not conflict with io.Reader. Similarly, the function to make new instances of ring.Ring—which is the definition of a constructor in Go—would normally be called NewRing, but since Ring is the only type exported by the package, and since the package is called ring, it's called just New, which clients of the package see asring.New. Use the package structure to help you choose good names.

包导入后 可以通过包名访问它的内容 这样带来的好处是 减少名字中的有重复含义的部分 例如 没必要在导入bufio包后 还使用BufReader来使用Reader 可以直接使用bufio.Reader 这样的使用方式给人的感觉更加简单明了 另外 包中内容总是通过包名来访问 所以bufio.Reader 就不会和 io.Reader冲突 同样地 创建ring.Ring的函数 在其它语言里可能被定义为NewRing 但是Ring就是唯一一个被导出的类型 而且包名是ring 那么可以函数名可以定义为New 使用的时候 调用ring.New

Another short example is once.Do; once.Do(setup) reads well and would not be improved by writing once.DoOrWaitUntilDone(setup). Long names don't automatically make things more readable. If the name represents something intricate or subtle, it's usually better to write a helpful doc comment than to attempt to put all the information into the name.

再举个例子 once.Do; once.Do(setup)就是一个很好的命名方式 写成once.DoOrWatiUnitDone(setup)并不会给理解这个函数的功能提供更多的信息 冗长的名字并不会让代码更加易读 如果名字需要表达复杂 或者光靠几个单词说不清楚的意思 那么最好还是加一段文档注释吧 (code complete里面也有推荐这样的方式)


Go doesn't provide automatic support for getters and setters. There's nothing wrong with providing getters and setters yourself, and it's often appropriate to do so, but it's neither idiomatic nor necessary to put Get into the getter's name. If you have a field called owner (lower case, unexported), the getter method should be called Owner (upper case, exported), not GetOwner. The use of upper-case names for export provides the hook to discriminate the field from the method. A setter function, if needed, will likely be called SetOwner. Both names read well in practice:

Go没有提供setter和getter的支持 但是只要你愿意 你来写也无妨 而且经常建议你这么做 但是在函数名里并不需要带个Get 如果有一个字段是owner 这个getter的名字可以直接定义为Owner 不要起GetOwner这样的名字 看着别扭 首字母大写作为可被导出的标识有点醒目哈 和其它的区别开 如果需要setter函数 这个可以定义为SetOwner

owner := obj.Owner()
if owner != user {

Interface names 接口命名

By convention, one-method interfaces are named by the method name plus the -er suffix: Reader, Writer, Formatter etc.

习惯上 只包含一个方法的接口命名时 在结尾加上er作为后缀 例如:Reader Writer Formatter等等

There are a number of such names and it's productive to honor them and the function names they capture. Read, Write, Close, Flush, String and so on have canonical signatures and meanings. To avoid confusion, don't give your method one of those names unless it has the same signature and meaning. Conversely, if your type implements a method with the same meaning as a method on a well-known type, give it the same name and signature; call your string-converter method String notToString.

使用这个规则命名的例子很多 Read Write Close Flush String等等有它们典型的申明特征和含义 相比之下 如果你的自定义类型实现了大家都认可的类型方法 给它定义相同的名字和申明 例如 把你的类型转换成string类型 给你的转换函数起名为String 而不是ToString


Finally, the convention in Go is to use MixedCaps or mixedCaps rather than underscores to write multiword names.

最后 Go使用骆驼式命名法 不用下划线的方式


Like C, Go's formal grammar uses semicolons to terminate statements; unlike C, those semicolons do not appear in the source. Instead the lexer uses a simple rule to insert semicolons automatically as it scans, so the input text is mostly free of them.

和C一样 Go使用分号结束语句 但是也有和C不同的放 在Go代码里通常看不到分号 词法分析器在分析源代码时 使用简易的规则来自动地插入分号

The rule is this. If the last token before a newline is an identifier (which includes words like int and float64), a basic literal such as a number or string constant, or one of the tokens

如果在换行符前的一个token是一个标识符(int float64之流), 数字或者字符串常量,亦或是以下几个token:

break continue fallthrough return ++ -- ) }

the lexer always inserts a semicolon after the token. This could be summarized as, “if the newline comes after a token that could end a statement, insert a semicolon”.


A semicolon can also be omitted immediately before a closing brace, so a statement such as

紧接在闭括号后的分号可以省略 就像下面这个例子:

    go func() { for { dst <- <-src } }()

needs no semicolons. Idiomatic Go programs have semicolons only in places such as for loop clauses, to separate the initializer, condition, and continuation elements. They are also necessary to separate multiple statements on a line, should you write code that way.

通常Go程序中使用分号的地方只有for循环 为了区分初始值 条件和后续的元素 如果同一行有多个语句 那么也需要使用分号 但还是一行一句吧 

One caveat. You should never put the opening brace of a control structure (if, for, switch, or select) on the next line. If you do, a semicolon will be inserted before the brace, which could cause unwanted effects. Write them like this

提醒一点 绝对不要把起始括号放在下一行(if for switch select语句中的括号) 如果你这样做了 词法分析器会插一个分号在括号前面 下面这个写法是正确的

if i < f() {

not like this 下面这个是错误的写法

if i < f()  // wrong!
{           // wrong!




查看原文:[翻译] effective go 之 Names Semicolons

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3362 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传