Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Golang中你可能不知的一些写法 #12

Open
zhouhaibing089 opened this issue Mar 15, 2016 · 1 comment
Open

Golang中你可能不知的一些写法 #12

zhouhaibing089 opened this issue Mar 15, 2016 · 1 comment
Labels

Comments

@zhouhaibing089
Copy link
Owner

zhouhaibing089 commented Mar 15, 2016

在阅读go代码的时候, 常常好奇代码的语义, 慢慢的便觉得好像挺有趣的, 因此在此写一篇短文来记录我所获悉的一点点奇技淫巧.

underscore import

来看段docker distribution项目中的代码:

package main

import (
    _ "net/http/pprof"

    "github.com/docker/distribution/registry"
    _ "github.com/docker/distribution/registry/auth/htpasswd"
    _ "github.com/docker/distribution/registry/auth/silly"
    _ "github.com/docker/distribution/registry/auth/token"
    _ "github.com/docker/distribution/registry/proxy"
    _ "github.com/docker/distribution/registry/storage/driver/azure"
    _ "github.com/docker/distribution/registry/storage/driver/filesystem"
    _ "github.com/docker/distribution/registry/storage/driver/gcs"
    _ "github.com/docker/distribution/registry/storage/driver/inmemory"
    _ "github.com/docker/distribution/registry/storage/driver/middleware/cloudfront"
    _ "github.com/docker/distribution/registry/storage/driver/oss"
    _ "github.com/docker/distribution/registry/storage/driver/s3-aws"
    _ "github.com/docker/distribution/registry/storage/driver/s3-goamz"
    _ "github.com/docker/distribution/registry/storage/driver/swift"
)

func main() {
    registry.RootCmd.Execute()
}

我们所知道_的语义常用在我们不想给变量命名的时候, 这出现在import语句中看起来就会显得有些奇怪——既然想隐藏这个名字, 那为何又要引入呢?

要理解这个问题, 不妨看看github.com/docker/distribution/registry/auth/htpassw有什么特殊的地方:

package htpasswd

import (
    "errors"
    "fmt"
    "net/http"
    "os"

    "github.com/docker/distribution/context"
    "github.com/docker/distribution/registry/auth"
)

// ...
func init() {
    auth.Register("htpasswd", auth.InitFunc(newAccessController))
}

我们知道当一个package被引入的时候, 它的init方法会被执行, 也就是说虽然我们不需要用到这个package, 却可以通过这种方式来触发执行它们的init方法.

underscore assign

就在上面代码所在的文件中, 同样有一处让人感到有点意外的代码:

package htpasswd

type accessController struct {
    realm    string
    htpasswd *htpasswd
}

var _ auth.AccessController = &accessController{}

你看, 我们声明了一个变量, 却没有给它一个名字, 这实在是有点匪夷所思, 不是嘛, :).

然细想, 这句话真得一点作用都没有吗? 好像真的是这么回事, 不过倘若我们退后一步想, 在编译时它却能确保: accessController implements auth.AccessController, 这样看来, 实在是用心良苦, 有木有!

three dots

倘若你看到这样一行代码:

var arr = [...]int{1, 2, 3}

你会不会大吃一惊, 这是什么鬼! 你也许知道golang有array和slice两种类型, 但这是什么东西, 会不会有点毫无头绪, 即使你知道C中的可变参数列表, 但拿这估计也是无能为力吧.

不过听我解释, 千万别觉得自己被耍了, 其实上面那行代码和下面完全等价:

var arr = [3]int{1, 2, 3}

它只不过是在编译时帮你把数组维度给计算出来了. 另外关于三点的可变参数语义和c, python等是一样的, 不足为奇, 遂不在此提及.

reassignment

很多情况下, 你可能会信手拈来就写上类似下面这样的代码, 却不曾仔细思考其中到底有何玄乎.

f, err := os.Open(name)
if err != nil {
    return err
}
d, err := f.Stat()
if err != nil {
    f.Close()
    return err
}

我们知道:=表示声明一个变量, 那为什么可以两次声明err变量呢? 哈哈, 是不是感觉被问我问倒啦..答案其实在官方文档中有所提及: 最重要的是只要至少声明一个新变量就可以, 其他的变量会变成重赋值, 因此在d, err := f.Stat()中, d是个新变量, 而 err已经被声明过了, 因此只是赋值而已.

struct{}

m := map[string]struct{}

怎么理解这个东西呢? 举几个例子就明了了:

// 这个可以work
m := make(map[string]struct{ Name string })
m["hello"] = struct{ Name string }{"world"}
// 这个也能work
type A struct {
    Name string
}
m := make(map[string]A)
m["hello"] = struct{ Name string }{"world"}
// 这个也还能work
type A struct {
    Name string
}
m := make(map[string]struct{ Name string })
m["hello"] = A{"world"}
// 即便这样也还是可以
type A struct {
    Name string
}
type B struct {
    Name string
}
m := make(map[string]struct{ Name string })
m["hello"] = A{"world"}
m["abc"] = B{"def"}
// 但是这个不能work
type A struct {
    Name string
}
type B struct {
    Name string
}
m := make(map[string]A)
m["hello"] = B{"world"}
@zhouhaibing089 zhouhaibing089 added blog and removed blog labels Dec 11, 2016
@GavinXu520
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants