We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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
在阅读go代码的时候, 常常好奇代码的语义, 慢慢的便觉得好像挺有趣的, 因此在此写一篇短文来记录我所获悉的一点点奇技淫巧.
来看段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语句中看起来就会显得有些奇怪——既然想隐藏这个名字, 那为何又要引入呢?
_
import
要理解这个问题, 不妨看看github.com/docker/distribution/registry/auth/htpassw有什么特殊的地方:
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方法.
init
就在上面代码所在的文件中, 同样有一处让人感到有点意外的代码:
package htpasswd type accessController struct { realm string htpasswd *htpasswd } var _ auth.AccessController = &accessController{}
你看, 我们声明了一个变量, 却没有给它一个名字, 这实在是有点匪夷所思, 不是嘛, :).
然细想, 这句话真得一点作用都没有吗? 好像真的是这么回事, 不过倘若我们退后一步想, 在编译时它却能确保: accessController implements auth.AccessController, 这样看来, 实在是用心良苦, 有木有!
倘若你看到这样一行代码:
var arr = [...]int{1, 2, 3}
你会不会大吃一惊, 这是什么鬼! 你也许知道golang有array和slice两种类型, 但这是什么东西, 会不会有点毫无头绪, 即使你知道C中的可变参数列表, 但拿这估计也是无能为力吧.
不过听我解释, 千万别觉得自己被耍了, 其实上面那行代码和下面完全等价:
var arr = [3]int{1, 2, 3}
它只不过是在编译时帮你把数组维度给计算出来了. 另外关于三点的可变参数语义和c, python等是一样的, 不足为奇, 遂不在此提及.
很多情况下, 你可能会信手拈来就写上类似下面这样的代码, 却不曾仔细思考其中到底有何玄乎.
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已经被声明过了, 因此只是赋值而已.
:=
err
d, err := f.Stat()
d
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"}
The text was updated successfully, but these errors were encountered:
吊
Sorry, something went wrong.
No branches or pull requests
在阅读go代码的时候, 常常好奇代码的语义, 慢慢的便觉得好像挺有趣的, 因此在此写一篇短文来记录我所获悉的一点点奇技淫巧.
underscore import
来看段docker distribution项目中的代码:
我们所知道
_
的语义常用在我们不想给变量命名的时候, 这出现在import
语句中看起来就会显得有些奇怪——既然想隐藏这个名字, 那为何又要引入呢?要理解这个问题, 不妨看看
github.com/docker/distribution/registry/auth/htpassw
有什么特殊的地方:我们知道当一个package被引入的时候, 它的
init
方法会被执行, 也就是说虽然我们不需要用到这个package, 却可以通过这种方式来触发执行它们的init
方法.underscore assign
就在上面代码所在的文件中, 同样有一处让人感到有点意外的代码:
你看, 我们声明了一个变量, 却没有给它一个名字, 这实在是有点匪夷所思, 不是嘛, :).
然细想, 这句话真得一点作用都没有吗? 好像真的是这么回事, 不过倘若我们退后一步想, 在编译时它却能确保: accessController implements auth.AccessController, 这样看来, 实在是用心良苦, 有木有!
three dots
倘若你看到这样一行代码:
你会不会大吃一惊, 这是什么鬼! 你也许知道golang有array和slice两种类型, 但这是什么东西, 会不会有点毫无头绪, 即使你知道C中的可变参数列表, 但拿这估计也是无能为力吧.
不过听我解释, 千万别觉得自己被耍了, 其实上面那行代码和下面完全等价:
它只不过是在编译时帮你把数组维度给计算出来了. 另外关于三点的可变参数语义和c, python等是一样的, 不足为奇, 遂不在此提及.
reassignment
很多情况下, 你可能会信手拈来就写上类似下面这样的代码, 却不曾仔细思考其中到底有何玄乎.
我们知道
:=
表示声明一个变量, 那为什么可以两次声明err
变量呢? 哈哈, 是不是感觉被问我问倒啦..答案其实在官方文档中有所提及: 最重要的是只要至少声明一个新变量就可以, 其他的变量会变成重赋值, 因此在d, err := f.Stat()
中,d
是个新变量, 而err
已经被声明过了, 因此只是赋值而已.struct{}
怎么理解这个东西呢? 举几个例子就明了了:
The text was updated successfully, but these errors were encountered: