Go 中显式作用域块的用途?
Purpose of an explicitly scoped block in Go?
我正在阅读 MicroMDM SCEP 存储库中的源代码,https://github.com/micromdm/scep/blob/1e0c4b782f3f2e1e6f81da5f82444a6cedc89df3/cmd/scepclient/scepclient.go#L54-L65:
func run(cfg runCfg) error {
ctx := context.Background()
var logger log.Logger
{
if strings.ToLower(cfg.logfmt) == "json" {
logger = log.NewJSONLogger(os.Stderr)
} else {
logger = log.NewLogfmtLogger(os.Stderr)
}
stdlog.SetOutput(log.NewStdlibAdapter(logger))
logger = log.With(logger, "ts", log.DefaultTimestampUTC)
if !cfg.debug {
logger = level.NewFilter(logger, level.AllowInfo())
}
}
lginfo := level.Info(logger)
我想知道显式块(外部{ ... }
)的目的是什么?这段代码会不会和去掉后完全一样,比如
func run(cfg runCfg) error {
ctx := context.Background()
var logger log.Logger
if strings.ToLower(cfg.logfmt) == "json" {
logger = log.NewJSONLogger(os.Stderr)
} else {
logger = log.NewLogfmtLogger(os.Stderr)
}
stdlog.SetOutput(log.NewStdlibAdapter(logger))
logger = log.With(logger, "ts", log.DefaultTimestampUTC)
if !cfg.debug {
logger = level.NewFilter(logger, level.AllowInfo())
}
lginfo := level.Info(logger)
也许显式块只是为了提高易读性?
在这种情况下,额外的块似乎没有任何意义。块内没有声明变量。它不会增加清晰度,反而会让您感到困惑。
如果需要清晰,您可以将该代码提取到一个新函数中以初始化记录器。
func initLogger(cfg runCfg) log.Logger {
var logger log.Logger
if strings.ToLower(cfg.logfmt) == "json" {
logger = log.NewJSONLogger(os.Stderr)
} else {
logger = log.NewLogfmtLogger(os.Stderr)
}
stdlog.SetOutput(log.NewStdlibAdapter(logger))
logger = log.With(logger, "ts", log.DefaultTimestampUTC)
if !cfg.debug {
logger = level.NewFilter(logger, level.AllowInfo())
}
return logger
}
func run(cfg runCfg) error {
ctx := context.Background()
logger := initLogger(cfg)
lginfo := level.Info(logger)
...
我最好的猜测是这个块在过去有过某种用途,但更改代码的人并没有删除它,也可能不确定是否仍然有用。翻看这个函数的blame log,或许会给你答案。
花点时间阅读其余代码,这些块是 all over the code。但在这些情况下,有 个声明的短期变量,这是一种在不再需要它们后丢弃它们的方法。两种最可能的情况是记录器可能有一些,或者它只是开发人员选择的特定样式。实际上,两者都可能是正确的。
对于 Go 来说,这有点奇怪,但可以有效地明确告诉垃圾收集器和开发人员这些已经超出范围。然而,Go 编译器和 GC 已经足够先进,知道什么时候可以丢弃它们,所以除了整理当前范围的命名空间之外,对程序本身没有什么好处。
虽然我同意@Schwern 的观点,但它增加了清晰度并实现了相同的结果,将它们重构为它们自己的函数。如果有人花时间明确声明作用域块,那么为什么不利用这段时间让它们发挥作用呢?
链接代码块:
var svc scepserver.Service // scep service
{
svcOptions := []scepserver.ServiceOption{
scepserver.ChallengePassword(*flChallengePassword),
scepserver.WithCSRVerifier(csrVerifier),
scepserver.CAKeyPassword([]byte(*flCAPass)),
scepserver.ClientValidity(clientValidity),
scepserver.AllowRenewal(allowRenewal),
scepserver.WithLogger(logger),
}
svc, err = scepserver.NewService(depot, svcOptions...)
if err != nil {
lginfo.Log("err", err)
os.Exit(1)
}
svc = scepserver.NewLoggingService(log.With(lginfo, "component", "scep_service"), svc)
}
var h http.Handler // http handler
{
e := scepserver.MakeServerEndpoints(svc)
e.GetEndpoint = scepserver.EndpointLoggingMiddleware(lginfo)(e.GetEndpoint)
e.PostEndpoint = scepserver.EndpointLoggingMiddleware(lginfo)(e.PostEndpoint)
h = scepserver.MakeHTTPHandler(e, svc, log.With(lginfo, "component", "http"))
}
我正在阅读 MicroMDM SCEP 存储库中的源代码,https://github.com/micromdm/scep/blob/1e0c4b782f3f2e1e6f81da5f82444a6cedc89df3/cmd/scepclient/scepclient.go#L54-L65:
func run(cfg runCfg) error {
ctx := context.Background()
var logger log.Logger
{
if strings.ToLower(cfg.logfmt) == "json" {
logger = log.NewJSONLogger(os.Stderr)
} else {
logger = log.NewLogfmtLogger(os.Stderr)
}
stdlog.SetOutput(log.NewStdlibAdapter(logger))
logger = log.With(logger, "ts", log.DefaultTimestampUTC)
if !cfg.debug {
logger = level.NewFilter(logger, level.AllowInfo())
}
}
lginfo := level.Info(logger)
我想知道显式块(外部{ ... }
)的目的是什么?这段代码会不会和去掉后完全一样,比如
func run(cfg runCfg) error {
ctx := context.Background()
var logger log.Logger
if strings.ToLower(cfg.logfmt) == "json" {
logger = log.NewJSONLogger(os.Stderr)
} else {
logger = log.NewLogfmtLogger(os.Stderr)
}
stdlog.SetOutput(log.NewStdlibAdapter(logger))
logger = log.With(logger, "ts", log.DefaultTimestampUTC)
if !cfg.debug {
logger = level.NewFilter(logger, level.AllowInfo())
}
lginfo := level.Info(logger)
也许显式块只是为了提高易读性?
在这种情况下,额外的块似乎没有任何意义。块内没有声明变量。它不会增加清晰度,反而会让您感到困惑。
如果需要清晰,您可以将该代码提取到一个新函数中以初始化记录器。
func initLogger(cfg runCfg) log.Logger {
var logger log.Logger
if strings.ToLower(cfg.logfmt) == "json" {
logger = log.NewJSONLogger(os.Stderr)
} else {
logger = log.NewLogfmtLogger(os.Stderr)
}
stdlog.SetOutput(log.NewStdlibAdapter(logger))
logger = log.With(logger, "ts", log.DefaultTimestampUTC)
if !cfg.debug {
logger = level.NewFilter(logger, level.AllowInfo())
}
return logger
}
func run(cfg runCfg) error {
ctx := context.Background()
logger := initLogger(cfg)
lginfo := level.Info(logger)
...
我最好的猜测是这个块在过去有过某种用途,但更改代码的人并没有删除它,也可能不确定是否仍然有用。翻看这个函数的blame log,或许会给你答案。
花点时间阅读其余代码,这些块是 all over the code。但在这些情况下,有 个声明的短期变量,这是一种在不再需要它们后丢弃它们的方法。两种最可能的情况是记录器可能有一些,或者它只是开发人员选择的特定样式。实际上,两者都可能是正确的。
对于 Go 来说,这有点奇怪,但可以有效地明确告诉垃圾收集器和开发人员这些已经超出范围。然而,Go 编译器和 GC 已经足够先进,知道什么时候可以丢弃它们,所以除了整理当前范围的命名空间之外,对程序本身没有什么好处。
虽然我同意@Schwern 的观点,但它增加了清晰度并实现了相同的结果,将它们重构为它们自己的函数。如果有人花时间明确声明作用域块,那么为什么不利用这段时间让它们发挥作用呢?
链接代码块:
var svc scepserver.Service // scep service
{
svcOptions := []scepserver.ServiceOption{
scepserver.ChallengePassword(*flChallengePassword),
scepserver.WithCSRVerifier(csrVerifier),
scepserver.CAKeyPassword([]byte(*flCAPass)),
scepserver.ClientValidity(clientValidity),
scepserver.AllowRenewal(allowRenewal),
scepserver.WithLogger(logger),
}
svc, err = scepserver.NewService(depot, svcOptions...)
if err != nil {
lginfo.Log("err", err)
os.Exit(1)
}
svc = scepserver.NewLoggingService(log.With(lginfo, "component", "scep_service"), svc)
}
var h http.Handler // http handler
{
e := scepserver.MakeServerEndpoints(svc)
e.GetEndpoint = scepserver.EndpointLoggingMiddleware(lginfo)(e.GetEndpoint)
e.PostEndpoint = scepserver.EndpointLoggingMiddleware(lginfo)(e.PostEndpoint)
h = scepserver.MakeHTTPHandler(e, svc, log.With(lginfo, "component", "http"))
}