Передача параметров процедурам и функциям в VBA, необязательные (optional) параметры, передача по ссылке (ByRef) и по значению (ByVal), применение ссылок при передаче параметров
Параметры — значения, которые передаются от одной процедуры другой. В принципе, можно обойтись и без параметров, воспользовавшись только переменными уровня модуля, но при использовании параметров читаемость программы улучшается. Чтобы процедура имела возможность принимать параметры, ее вначале нужно объявить с параметрами. Например, вот пример простой функции, которая складывает два числа и выводит результат:
Function fSum (nItem1 As Integer, nItem2 As Integer)
fSum = nItem1 + nItem2
End Function
Вызов ее может выглядеть так:
MsgBox(fSum(3, 2))
В данном случае мы объявили оба параметра как обязательные, и поэтому попытка вызвать функцию без передачи ей какого-либо параметра (например, так: MsgBox (fSum(3))) приведет к ошибке "Argument not optional" — "Параметр не является необязательным". Чтобы можно было пропускать какие-то параметры, эти параметры можно сделать необязательными. Для этой цели используется ключевое слово Optional:
Function fSum (nItem1 As Integer, Optional nItem2 As Integer)
В справке по встроенным функциям VBA необязательные параметры заключаются в квадратные скобки.
Для проверки того, был ли передан необязательный параметр, используется либо функция IsMissing (если для этого параметра был использован тип Variant), либо его значение сравнивается со значениями переменных по умолчанию (ноль для числовых данных, пустая строка для строковых и т.п.)
Вызов функции с передачей параметров может выглядеть так:
nResult = fSum (3, 2)
Однако здесь есть несколько моментов, которые необходимо рассмотреть.
В нашем примере мы передаем параметры по позиции, то есть значение 3 присваивается первому параметру (nItem1), а значение 2 — второму (nItem2). Однако параметры можно передавать и по имени:
nResult = fSum (nItem 1 := 3, nItem 2 := 2)
Обратите внимание, что несмотря на то, что здесь выполняется вполне привычная операция — присвоение значений, оператор присвоения используется не совсем обычный — двоеточие со знаком равенства, как в C++. При использовании знака равенства возникнет ошибка.
Конечно, вместо явной передачи значений (как у нас — 3 и 2) можно использовать переменные. Однако что произойдет с переменными после того, как они "побывают" в функции, если функция изменяет их значение? Останется ли это значение за пределами функции прежним или изменится?
Все зависит от того, как именно передаются параметры — по ссылке (по умолчанию, можно также использовать ключевое слово ByRef или по значению — нужно использовать ключевое слово ByVal).
Если параметры передаются по ссылке, то фактически в вызываемую процедуру передается ссылка на эту переменную в оперативной памяти. Если эту переменную в вызываемой процедуре изменить, то значение изменится и в вызывающей функции. Это — принятое в VBA поведение по умолчанию.
Если параметры передаются по значению, то фактически в оперативной памяти создается копия этой переменной и вызываемой процедуре передается эта копия. Конечно же, чтобы вы не сделали с этой копией, на исходную переменную это никак не повлияет и в вызывающей процедуре не отразится.
Продемонстрировать разницу можно на простом примере:
Private Sub TestProc ()
'Объявляем переменную nPar1 и присваиваем ей значение
Dim nPar1 As Integer
nPar1 = 5
'Передаем ее как параметр nItem1 функции fSum
MsgBox (fSum(nItem1:=nPar1, nItem2:=2))
'А теперь проверяем, что стало в нашей переменной nPar1, 'после того, как она побывала в функции fSum:
MsgBox nPar1
End Sub
Function fSum(nItem1 As Integer, nItem2 As Integer)
'Используем значение переменной
fSum = nItem 1 + nItem 2
'А затем ее меняем!
nItem 1 = 10
End Function
Проверьте, что будет, если поменять строку объявления функции
Function fSum(nItem1 As Integer, nItem2 As Integer)
на следующую строку :
Function fSum(byVal nItem1 As Integer, nItem2 As Integer)
Можно продемонстрировать компилятору VBA, что то, что возвращает функция, наш совершенно не интересует. Для этого достаточно не заключать ее параметры в круглые скобки. Например, в случае со встроенной функцией MsgBox это может выглядеть так:
MsgBox "Test"
а для нашей функции —
fSum 3, 2
Такой код будет работать совершенно нормально. Однако, если нам потребуется все-таки узнать, что возвращает MsgBox, то придется передаваемые ему параметры заключать в круглые скобки:
nTest = MsgBox("Test")
Для многих встроенных функций компилятор VBA в принципе не дает возможности игнорировать возвращаемое значение, заставляя помещать параметры в круглые скобки и принимать возвращаемое значение.