Цель явно ограниченного блока в Go? - PullRequest
0 голосов
/ 10 октября 2019

Я читаю этот исходный код в репозитории 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)

Возможно, явный блок просто для улучшения разборчивости?

Ответы [ 2 ]

5 голосов
/ 10 октября 2019

В этом случае, кажется, нет никакой цели для дополнительного блока. Внутри блока не объявляются переменные. Это не добавляет ясности, вместо этого это сбивает вас с толку.

Если бы ясность была желательна, вы извлекли бы этот код в новую функцию для инициализации регистратора.

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)
    ...

Мое лучшее предположение:этот блок служил какой-то цели в прошлом, и тот, кто изменил код, не удалял его, возможно, также не был уверен, что все еще служит цели. Просмотр журнала обвинений этой функции может дать вам ответ.

2 голосов
/ 10 октября 2019

Потратив минуту на чтение остальной части кода, эти блоки по всему коду . В этих случаях, однако, являются недолговечными переменными, которые объявлены, и это метод для отбрасывания их после того, как они больше не нужны. Два наиболее вероятных сценария состоят в том, что для регистратора могут быть какие-то сценарии или что это просто особый стиль, выбранный разработчиком. На самом деле, оба, скорее всего, верны.

Это немного странный стиль для 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"))
}
...