[翻譯] 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 聲明的含義是 這個賦值只是爲了類型檢查 而不是要建立一個變量 通常來說 若是代碼中沒有其它的靜態轉換時 纔會用這招

相關文章
相關標籤/搜索