[翻译] effective go 之 Blank identifier

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. html

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


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. json

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

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. ide

另外一个经常使用的地方 就是函数调用 返回一个值和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. oop

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

// 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. ui

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


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 声明的含义是 这个赋值只是为了类型检查 而不是要建立一个变量 通常来说 若是代码中没有其它的静态转换时 才会用这招

相关文章
相关标签/搜索