這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
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 := 0for _, 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 mainimport ( "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 mainimport ( "fmt" "io")var _ = fmt.Printfvar _ io.Readerfunc 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 聲明的含義是 這個賦值只是為了類型檢查 而不是要建立一個變數 一般來講 如果代碼中沒有其它的靜態轉換時 才會用這招