《Effective Go》--空白标识符

前端之家收集整理的这篇文章主要介绍了《Effective Go》--空白标识符前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

未使用的导入和变量

    如果你在程序中导入了一个包或声明了一个变量却没有使用的话,会引起编译错误。因为,导入未使用的包不仅会使程序变得臃肿,同时也降低了编译效率;初始化 一个变量却不使用,轻则造成对计算的浪费,重则可能会引起更加严重BUG。当一个程序处于开发阶段时,会存在一些暂时没有被使用的导入包和变量,如果为了 使程序编译通过而将它们删除,那么后续开发需要使用时,又得重新添加,这非常麻烦。空白标识符为上述场景提供了解决方案。

    以下一段代码包含了两个未使用的导入包(fmt和io) 以及一个未使用的变量(fd),因此无法编译通过。我们可能希望这个程序现在就可以正确编译。

package main

import (
    "fmt"
    "io"
    "log"
    "os"
)

func main() {
    fd,err := os.Open("test.go")
    if err != nil {
        log.Fatal(err)
    }
    // TODO: use fd.
}

    为了禁止编译器对未使用导入包的错误报告,我们可以用空白标识符来引用一个被导入包中的符号。同样的,将未使用的变量fd赋值给一个空白标识符也可以禁止编译错误。这个版本的程序就可以编译通过了。

package main

import (
    "fmt"
    "io"
    "log"
    "os"
)

var _ = fmt.Printf // For debugging; delete when done.
var _ io.Reader    // For debugging; delete when done.

func main() {
    fd,err := os.Open("test.go")
    if err != nil {
        log.Fatal(err)
    }
    // TODO: use fd.
    _ = fd
}

    按照约定,用来临时禁止未使用导入错误的全局声明语句必须紧随导入语句块之后,并且需要提供相应的注释信息 —— 这些规定使得将来很容易找并删除这些语句。

副作用式导入

    像上面例子中的导入的包,fmt或io,最终要么被使用,要么被删除:使用空白标识符只是一种临时性的举措。但有时,导入一个包仅仅是为了引入一些副作用,而不是为了真正使用它们。例如,net/http/pprof包会在其导入阶段调用init函数,该函数注册HTTP处理程序以提供调试信息。这个包中确实也包含一些导出的API,但大多数客户端只会通过注册处理函数的方式访问web页面的数据,而不需要使用这些API。为了实现仅为副作用而导入包的操作,可以在导入语句中,将包用空白标识符进行重命名

import _ "net/http/pprof"

    这一种非常干净的导入包的方式,由于在当前文件中,被导入的包是匿名的,因此你无法访问包内的任何符号。(如果导入的包不是匿名的,而在程序中又没有使用到其内部的符号,那么编译器将报错。)

接口检查

    一个类型不需要明确的声明它实现了某个接口。一个类型要实现某个接口,只需要实现该接口对应的方法就可以了。在实际中,多数接口的类型转换和检查都是在编译阶段静态完成的。例如,将一个*os.File类型传入一个接受io.Reader类型参数的函数时,只有在*os.File实现了io.Reader接口时,才能编译通过。

    但是,也有一些接口检查是发生在运行时的。其中一个例子来自encoding/json包内定义的Marshaler接口。当JSON编码器接收到一个实现了Marshaler接口的参数时,就调用该参数的marshaling方法来代替标准方法处理JSON编码。编码器利用类型断言机制在运行时进行类型检查:

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

    假设我们只是想知道某个类型是否实现了某个接口,而实际上并不需要使用这个接口本身 —— 例如在一段错误检查代码中 —— 那么可以使用空白标识符来忽略类型断言的返回值:

if _,ok := val.(json.Marshaler); ok {
    fmt.Printf("value %v of type %T implements json.Marshaler\n",val,val)
}

    在某些情况下,我们必须在包的内部确保某个类型确实满足某个接口的定义。例如类型json.RawMessage,如果它要提供一种定制的JSON格式,就必须实现json.Marshaler接口,但是编译器不会自动对其进行静态类型验证。如果该类型在实现上没有充分满足接口定义,JSON编码器仍然会工作,只不过不是用定制的方式。为了确保接口实现的正确性,可以在包内部,利用空白标识符进行一个全局声明:

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

    在该声明中,赋值语句导致了从*RawMessage到Marshaler的类型转换,这要求*RawMessage必须正确实现了Marshaler接口,该属性将在编译期间被检查。当json.Marshaler接口被修改后,上面的代码将无法正确编译,因而很容易发现错误并及时修改代码

    在这个结构中出现的空白标识符,表示了该声明语句仅仅是为了触发编译器进行类型检查,而非创建任何新的变量。但是,也不需要对所有满足某接口的类型都进行这样的处理。按照约定,这类声明仅当代码中没有其他静态转换时才需要使用,这类情况通常很少出现。

本文整理自:https://www.kancloud.cn/kancloud/effective/72211

个人微信公众号:

作者:jiankunking 出处:@L_301_1@

猜你在找的Go相关文章