#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
Что делает функция, так это берет заголовок таблицы и создает словарь имен столбцов и соответствующих индексов, так что порядок столбцов не важен для остальной части кода.
Мой вопрос таков: необходимо ли использовать отдельную переменную для сохранения значения на протяжении всего цикла, или я могу
- редактируйте возвращаемое значение («get_header») все время вместо того, чтобы передавать значение только в конце или
- используйте структуру 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
по многим причинам. Однако, даже если ошибки не являются «тихими», использование имени функции в качестве переменной может потребовать более тщательного упреждающего отслеживания ошибок внутри функции.