Использовать переменную внутри функции или использовать саму функцию?

#excel #vba

#excel #vba

Вопрос:

У меня есть эта функция в моем коде:

 Function get_header(ByVal rw As Range) As Scripting.Dictionary
    Dim header    As New Scripting.Dictionary
    Dim used      As Range

    Set used = Range(rw.Cells(1, 1), rw.Cells(1, rw.Cells(1, rw.Columns.Count).End(xlToLeft).Column))

    For Each cl In used.Cells
        header.Add cl.Value, cl.Column
    Next
    
    Set get_header = header
End Function
  

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

Мой вопрос таков: необходимо ли использовать отдельную переменную для сохранения значения на протяжении всего цикла, или я могу

  1. редактируйте возвращаемое значение («get_header») все время вместо того, чтобы передавать значение только в конце или
  2. используйте структуру With следующим образом:
 Function get_header(ByVal rw As Range) As Scripting.Dictionary
    Dim used      As Range

    With rw
        Set used = Range(.Cells(1, 1), .Cells(1, .Cells(1, .Columns.Count).End(xlToLeft).Column))
    End With

    With get_header
        For Each cl In used.Cells
            .Add cl.Value, cl.Column
        Next
    End With

End Function
  

Кроме того, почему я должен использовать любую из этих структур вместо других?
Спасибо за любой совет, ребята.

Комментарии:

1. Поскольку это в конечном счете основано на мнении, я голосую за вариант № 1. # 2 как бы скрывает возвращаемое значение для меня, в то время как # 1 является явным, насколько это возможно.

2. Помимо того, что ваш вопрос основан на мнении, он сбивает с толку в том смысле, что оба ваших # 1 и # 2 касаются использования имени функции в качестве переменной в теле функции и, таким образом, на самом деле не иллюстрируют контраст, который вы, похоже, пытаетесь создать.

3. К вашему СВЕДЕНИЮ, эта строка Set used = Range(rw.Cells(1, 1), ... в обычном модуле code выдаст ошибку, если лист с rw не активен. Что-то вроде Set used = rw.Parent.Range(rw.Cells(1, 1), ... было бы более надежным.

Ответ №1:

Хотел прокомментировать это, но слишком длинно для комментария:

Когда у меня есть функция, которая «вычисляет» возвращаемое значение шаг за шагом, я обычно предпочитаю иметь промежуточную переменную по следующим причинам (обратите внимание, что использование дополнительных переменных не требует затрат во время выполнения, это не проблема):

  • Именование: Мне не нравится присваивать значения чему-то, что вызывается getSomething .
  • при использовании с правой стороны это позволяет избежать двусмысленности между «промежуточным» значением и рекурсивным вызовом функции: getSomething = getSomething getSomething(p) . Компилятор может справиться с этим, но мой мозг? Не так много. Я считаю, retVal = retVal getSomething(p) это намного понятнее.
  • При запуске с ошибкой в середине выполнения я могу легко выполнить Exit Function , не думая о том, что уже было вычислено.

Но, в конце концов (и это справедливо также для вопроса «если» или «если не использовать With -инструкцию»), есть две вещи, которые имеют значение: (1) Какой код легче читать и понимать. и (2) Какой код с меньшей вероятностью содержит ошибку.Поскольку человеческий мозг работает по-разному, найдите свой личный стиль и придерживайтесь его.

Комментарии:

1. Я тоже предпочитаю этот подход. Во-первых, в большинстве языков программирования есть, return так что return calculated_value это единственный вариант. Использование идиомы function_name = calculated_value позволяет понять, что именно возвращает функция, тогда как если у вас есть несколько строк, подобных function_name = possibly_intermediate_value , может быть неясно, какая именно строка выполняет функцию возврата.

Ответ №2:

Я бы предпочел ваш первый пример вместо того, чтобы редактировать возвращаемое значение функции более одного раза за один вызов функции.

В зависимости от того, прерывается ли отслеживание ошибок или выполняется беззвучно (т.Е. on error resume next ), вы можете получить разные и непреднамеренные результаты. Важно отметить, что вы можете получить непреднамеренные результаты и не знать об этом.

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

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

Ваш первый блок кода, похоже, уже соответствует этому мышлению. Каждое из ваших альтернативных предложений 1 и 2 этого не делает.

Комментарии:

1. «Я бы рекомендовал кодирование, чтобы избежать этой ситуации» … кажется, это причина избегать On Error Resume Next (одна из многих), а не причина не использовать имя функции в качестве переменной.

2. @JohnColeman Это предполагает, что OP контролирует обработку ошибок во всем пространстве процедур. Я согласен, что часто лучше не использовать On Error Resume Next по многим причинам. Однако, даже если ошибки не являются «тихими», использование имени функции в качестве переменной может потребовать более тщательного упреждающего отслеживания ошибок внутри функции.