[翻译] effective go 之 Blank identifier

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

Blank identifier

Go defines a special identifier _, called the blank identifier. The blank identifier can be used in a declaration to avoid declaring a name, and it can be used in an assignment to discard a value. This definition makes it useful in a variety of contexts.

Go中有一个特殊的标识符 _ 被成为blank identifier 它可以用来避免为某个变量起名 同时也可以在赋值时 舍弃某个值


Multiple assignment

If an assignment requires multiple values on the left side, but one of the values will not be used by the program, using the blank identifier in the assignment avoids the need to create a dummy variable. We saw one example of this in the discussion of for loops above.

如果赋值时 需要在赋值语句左边 也就是等号的左边 同时给多个变量赋值 但是其中的某个值 不会再次被程序使用到 使用black identifier 可以避免创建一个没用的变量 看下面这个例子:

sum := 0
for _, value := range array { // 我们不关心index的值
    sum += value
}


Another common use is when calling a function that returns a value and an error, but only the error is important.

另一个常用的地方 就是函数调用 返回一个值和error 但是我们只关心这个error:

if _, err := os.Stat(path); os.IsNotExist(err) {
	fmt.Printf("%s does not exist\n", path)
}


A final use that is more common than it should be is to discard the error from a function that is not expected to fail. This is usually a mistake: when the function does fail, the code will continue on and probably panic dereferencing a nil pointer.

还有一个常用的地方 舍弃函数调用返回的error 而这个函数调用的期望结果是它一定不会产生error 这种用法可能是错误的 如果函数确实返回了error 接下来的代码可能会产生panic

// Always check errors: this program crashes if path does not exist.
fi, _ := os.Stat(path)
fmt.Printf("%s is %d bytes\n", path, fi.Size())


Unused imports and variables

Go defines that it is an error to import a package without using it, or to declare a variable without using its value. Unused imports bloat a program and lengthen compiles unnecessarily; a variable that is initialized but not used is at least a wasted computation and perhaps indicative of a larger bug. Of course, both of these situations also arise in programs that are under active development, as you test and refine your code.

在Go中 如果导入了某个包 但是并有使用它 Go会认为这是个错误的状态 编译过不去 导入包 但是不用它 可能会出现意想不到的情况 而且给编译增加了不必要的麻烦 已经初始化过 但是没有使用的变量会浪费计算资源 并且时间久了之后 或者他人接受后 可能会不注意到这点 而导致严重的bug


For example, in this program, there are two unused imports (fmt and io) and an unused variable (greeting).

举例来说 在下面这段代码中 有两个导入的包 以及一个变量 没有被使用:

package main

import (
    "fmt"
    "io"
)

func main() {
    greeting := "hello, world"
}


Top-level blank declarations referring to the packages will silence the unused import errors. By convention, these declarations should come immediately after the imports, as a reminder to clean things up later. Similarly, assigning greeting to a blank identifier will silence the unused variable error.

全局层面的blank声明 可以抑制导入但是没有使用的错误 通常来讲 在导入不会被使用的包之后 就需要立刻做blank声明 

package main

import (
    "fmt"
    "io"
)

var _ = fmt.Printf
var _ io.Reader

func main() {
    greeting := "hello, world"
    _ = greeting
}


Import for side effect 

An unused import like fmt or io in the last section should eventually be used or removed: blank assignments identify code as a work in progress. But sometimes it is useful to import a package only for its side effects, without any explicit use. For example, during its init function, the net/http/pprof package registers HTTP handlers that provide useful debugging information. It has an exported API too, but most clients need only the handler registration. In this situation, it is conventional to rename the package to the blank identifier:

没有用处的导入 像上面那段代码中的fmt和io包 最终应该被使用 或者被移除 做blank声明尽是起提醒的作用 告诉我们 这段代码我们还在完善中 但是有些时候 我们确需要导入那些不被使用的包 因为我们想使用包中的某些内容 比如 包net/http/pprof中的init函数 它的init函数会注册一个处理HTTP请求的handler 这个handler提供了调试的信息 net/http/pprof也有可被导出的API 但是大多数情况下 我们只想要init函数提供的功能 如果遇到这种场景 通常的做法是 在导入时 使用blank identifier给包起名:

import _ "net/http/pprof"

This form of import makes clear that the package is being imported for its side effects, because there is no other possible use of the package: in this file, it doesn't have a name.

这种形式的导入方式 明确地告知了 我们导入这个包 就是要这个包的某些附加效应


Interface checks

As we saw in the discussion of interfaces above, Go does not require a type to declare explicitly that it implements an interface. It implements the interface by simply implementing the required methods. This makes Go programs more lightweight and flexible, and it can avoid unnecessary dependencies between packages. Most interface conversions are static, visible to the compiler, and therefore checked at compile time. For example, passing an *os.File to a function expecting an io.Reader will not compile unless *os.File implements the io.Reader interface.

正如我们在讨论interface的时候那样 Go并不要求必须一个类型必须显式地声明 它实现这个接口 只要是实现了接口中定义的函数 就是实现了相应的接口 这使得Go程序大多数都是轻量级的 并且很灵活 而且Go程序避免了不必要的包依赖 大多数接口转换都是静态的 对编译器是可见的 因此 Go在编译的时候检查接口 比如 给只接受io.Reader的函数传递*os.File 就会导致编译过不去 除非*os.File实现了io.Reader接口


However, some types that are used only to satisfy dynamic interface checks. For example, the encoding/json package defines a Marshaler interface. If the JSON encoder encounters a type implementing that interface, the encoder will let the type convert itself to JSON instead of using the standard conversion. This check is done only at runtime, with code like:

然而 一些类型仅是用来满足动态接口检查的要求 比如 encoding/json包 定义了Marshaler接口 如果JSON的解码器遇到实现了该接口的类型 解码器会使用这个类型自己的方法转换为JSON 而不是用标准的转换方式 这个检查只发生在运行时 代码如下:

m, ok := val.(json.Marshaler)


If a type—for example, json.RawMessage—intends to customize its JSON representation, it should implement json.Marshaler, but there are no static conversions that would cause the compiler to verify this automatically. A declaration can be used to add such a check:

如果json.RawMessage类型想定制JSON表达方式 json.RawMessage类型就需要实现json.Marshaler接口 但是这个转换并不是静态的 编译器无法去检查是否有错误 可以通过声明来要求编译器做检查:

var _ json.Marshaler = (*MyMessage)(nil)

As part of type-checking this static assignment of a *RawMessage to a Marshaler, the Go compiler will require that *RawMessage implements Marshaler. Using the blank identifier here indicates that the declaration exists only for the type checking, not to create a variable. Conventionally, such declarations are used only when there are no static conversions already present in the code.

这个声明语句把*RawMEssage赋值给了Marshaler Go编译器会要求*RawMessage实现了Marshaler接口 这里的blank 声明的含义是 这个赋值只是为了类型检查 而不是要创建一个变量 一般来讲 如果代码中没有其它的静态转换时 才会用这招


有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:pengfei_xue

查看原文:[翻译] effective go 之 Blank identifier

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

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