Стоимость определения структур golang при вызове функции

Я наткнулся на функцию, которая определяет свои собственные типы запросов и ответов.

func doSomething() {

    type request struct {
        resourceID string
    }

    type response struct {
        resourceContents *Data
    }

    request := initializeRequest()
    result := dispatchRequest(request)

    ...
}

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

Однако меня беспокоит стоимость этого: намного ли дороже иметь вызов функции, объявляющий свой собственный тип, по сравнению с объявлением этого типа в области пакета?

Кроме того, является ли этот подход идиоматичным?


person levelont    schedule 17.01.2019    source источник
comment
Дополнительная плата не взимается. Определение относится только к функции, а не к пакету.   -  person Flimzy    schedule 17.01.2019
comment
У @Flimzy есть. Чтобы добавить некоторые подробности, Go статически типизируется во время компиляции, что означает, что определение типа не выполняется каждый раз при вызове функции — оно не выполняется вообще. Он оценивается только во время компиляции, просто если он определен внутри функции, это единственное место, где можно сослаться на имя этого типа.   -  person Adrian    schedule 17.01.2019
comment
И если будут затраты времени выполнения (ЦП или аллоков): Напишите бенчмарк и посмотрите, не повредит ли это вашему варианту использования.   -  person Volker    schedule 17.01.2019
comment
Очень ценю быстрые ответы, особенно метафору казни!   -  person levelont    schedule 17.01.2019


Ответы (1)


Типы — это концепция времени компиляции, и их область действия не будет (как правило) влиять на скорость выполнения, поскольку код, который компилятор генерирует в этих случаях, не обращает внимания на исходный тип (подробнее читайте на Введите стирание и овеществление), причем отражение является исключением, но здесь у вас нет отражения.


Тем не менее, я нахожу этот код немного подозрительным:

request := initializeRequest()

Где определяется initializeRequest? Он должен знать о типе request, поэтому я предполагаю, что он также является внутренним для функции? В противном случае код не будет компилироваться. Эти соображения во многих случаях ограничивают полезность структур, локальных для функций, но если у вас все локально, я думаю, что хорошей практикой будет максимальное скрытие типов.

В более масштабных программах также встанет вопрос тестирования. Как вы тестируете типы и функции, работающие с ними, если они скрыты в области видимости?

person Eli Bendersky    schedule 17.01.2019
comment
Другое ограничение состоит в том, что такие типы не могут иметь методов (и, соответственно, не могут реализовывать интерфейсы). Это делает их буквально просто типами данных. Я использую их все время для одноразовой сортировки и демаршаллинга. - person Peter; 17.01.2019
comment
Спасибо за ваше наблюдение, @Peter: именно в рамках сортировки и десортировки я использую эти типы. - person levelont; 18.01.2019