Необязательные параметры

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

Листинг 9.6. Необязательные параметры

Function Сумма(a As Integer, Optional b As Integer = 2) As Integer
   Сумма = a + b
End Function
...
' Вызов функции
Debug.Print Сумма(5)      ' 7
Debug.Print Сумма(10, 50) ' 60

Таким образом, если второй параметр не задан, то его значение будет равно 2. Обратите внимание на то, что необязательные параметры должны следовать после обязательных параметров, иначе будет выведено сообщение об ошибке.

До сих пор мы использовали позиционную передачу параметров в подпрограмму:

Function Сумма(a As Integer, Optional b As Integer = 2) As Integer
   Сумма = a + b
End Function
...
' Вызов функции
Debug.Print Сумма(10, 20)

Переменной a при сопоставлении будет присвоено значение 10, а переменной b — значение 20. Язык VBA позволяет также передать значения в подпрограмму, используя сопоставление по ключам (листинг 9.7). Для этого при вызове подпрограммы параметрам присваиваются значения через оператор :=. Последовательность указания параметров может быть произвольной.

Листинг 9.7. Сопоставление по ключам

Debug.Print Сумма(b:=50, a:=10)     ' 60

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

Function Сумма(Optional a As Integer = 2, Optional b As Integer = 3, _
               Optional c As Integer = 4) As Integer
   ' Все параметры являются необязательными
   Сумма = a + b + c
End Function
...
' Вызов функции
Debug.Print Сумма(2, 3, 20) ' Позиционное присваивание
Debug.Print Сумма(c:=20)    ' Сопоставление по ключам

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

Debug.Print Сумма(, , 20)

Таким способом удобно пользоваться при небольшом количестве необязательных параметров. Если необязательных параметров много, то лучше воспользоваться сопоставлением по ключам.

Функция IsMissing() позволяет определить передан ли необязательный параметр при вызове подпрограммы. Если параметр не был передан, то функция возвращает значение True, в противном случае — значение False. Обратите внимание на то, что проверить можно только параметры имеющие тип Variant, для остальных типов следует использовать значения по умолчанию. Переделаем нашу функцию суммирования трех чисел и используем функцию IsMissing() для указания значений по умолчанию (листинг 9.8).

Листинг 9.8. Функция IsMissing()

Function Сумма(Optional a As Variant, Optional b As Variant, _
               Optional c As Variant) As Variant
   If IsMissing(a) = True Then
      a = 2
   End If
   If IsMissing(b) = True Then
      b = 3
   End If
   If IsMissing(c) = True Then
      c = 4
   End If
   Сумма = a + b + c
End Function

Переменное число параметров

Если перед параметром в определении подпрограммы указать ключевое слово ParamArray, то подпрограмме можно будет передать произвольное количество параметров. Все переданные значения сохраняются в массиве. Обратите внимание на то, что массив должен быть обязательно объявлен с типом Variant, другие типы данных не поддерживаются. В качестве примера напишем функцию суммирования произвольного количества чисел (листинг 9.10).

Листинг 9.10. Сохранение переданных данных в массиве

Function Сумма(ParamArray Массив() As Variant) As Variant
   Dim Item As Variant, Итог As Variant
   Итог = 0
   For Each Item In Массив
      Итог = Итог + Item
   Next
   Сумма = Итог
End Function
...
' Вызов функции
Debug.Print Сумма(10, 20)                 ' 30
Debug.Print Сумма(10, 20, 30, 40, 50, 60) ' 210

Можно также вначале указать несколько обязательных параметров, однако смешивать необязательные параметры и параметр с ключевым словом ParamArray нельзя. Пример:

Function Сумма(a As Variant, ParamArray Массив() As Variant) As Variant
   Dim Item As Variant, Итог As Variant
   Итог = a
   For Each Item In Массив
      Итог = Итог + Item
   Next
   Сумма = Итог
End Function

Способы передачи параметров

Параметры в подпрограмму можно передавать двумя способами: по значению и по ссылке. При передачи по значению производится копирование значения. Любое изменение значения внутри подпрограммы не затронет исходное значение. Чтобы иметь возможность передать параметр по значению, в определении подпрограммы перед именем параметра следует указать ключевое слово ByVal. Создадим функцию и внутри нее попытаемся изменить значение параметра (листинг 9.11).

Листинг 9.11. Передача параметра по значению

Function Сумма(ByVal a As Variant, ByVal b As Variant) As Variant
   ' Передача параметров по значению
   a = a + 20
   Сумма = a + b
End Function
...
' Вызов функции
Dim x As Integer
x = 50
Debug.Print Сумма(x, 5)   ' 75
Debug.Print x             ' 50

Как видно из результата, попытка изменить значение внутри функции не привела к изменению исходного значения в переменной x. Однако, если использовать передачу параметра по ссылке, то ситуация изменится (листинг 9.12).

Листинг 9.12. Передача параметра по ссылке

Function Сумма(ByRef a As Variant, ByRef b As Variant) As Variant
   ' Передача параметров по ссылке
   a = a + 20
   Сумма = a + b
End Function
...
' Вызов функции
Dim x As Integer
x = 50
Debug.Print Сумма(x, 5)   ' 75
Debug.Print x             ' 70

В этом примере, перед именем параметра указано ключевое слово ByRef, которое означает, что параметр передается в функцию по ссылке. Обратите внимание на то, что значение в переменной x изменилось. Передачу параметра по ссылке удобно использовать при обработке данных, имеющих большой размер. В этом случае копирование значения не производится и тем самым экономится память. В других ситуациях следует избегать изменения значения внутри подпрограммы.

Следует учитывать, что:

Передача массива в качестве параметра

Чтобы в подпрограмму передать массив, следует параметр объявить как динамический массив. В качестве примера напишем программу суммирования элементов массива (листинг 9.13).

Листинг 9.13. Передача массива в качестве параметра

Function Сумма(Массив() As Integer) As Integer
   Dim Item As Variant, Итог As Integer
   Итог = 0
   For Each Item In Массив
      Итог = Итог + Item
   Next
   Сумма = Итог
End Function
...
' Вызов функции
Dim arr(2) As Integer
arr(0) = 10
arr(1) = 20
arr(2) = 30
Debug.Print Сумма(arr)   ' 60

Массив в подпрограмму передается только по ссылке, поэтому внутри подпрограммы можно изменять значения элементов массива. Например, умножим все значения элементов массива на 2 (листинг 9.14).

Листинг 9.14. Измение элементов массива внутри подпрограммы

Sub ИзменениеМассива(Массив() As Integer)
   Dim i As Integer
   For i = LBound(Массив) To UBound(Массив)
      Массив(i) = Массив(i) * 2
   Next
End Sub
...
' Вызов функции
Dim arr(2) As Integer, i As Integer
arr(0) = 10
arr(1) = 20
arr(2) = 30
ИзменениеМассива arr
For i = LBound(arr) To UBound(arr)
   Debug.Print arr(i)
Next

Если массив содержится в переменной типа Variant, то параметр в подпрограмме объявляется с типом Variant. В этом случае массив можно передавать как по ссылке, так и по значению. В качестве примера напишем функцию нахождения минимального значения массива (листинг 9.15).

Листинг 9.15. Нахождение минимального значения в массиве

Function Min(Массив As Variant) As Variant
   Dim МинЗнач As Variant, i As Integer
   МинЗнач = Массив(0)
   For i = LBound(Массив) To UBound(Массив)
      If Массив(i) < МинЗнач Then
         МинЗнач = Массив(i)
      End If
   Next
   Min = МинЗнач
End Function
...
' Вызов функции
Dim arr As Variant
arr = Array(10, 20, 30, 5, 80)
Debug.Print Min(arr) ' 5

Преждевременное завершение подпрограмм

Для преждевременного завершения выполнения процедуры предназначена инструкция Exit Sub. Чтобы преждевременно завершить функцию следует воспользоваться инструкцией Exit Function. В качестве примера создадим функцию деления двух целых чисел с обработкой деления на 0 (листинг 9.16).

Листинг 9.16. Инструкция Exit Function

Function Деление(x As Integer, y As Integer) As Double
   If y = 0 Then
      Деление = 0
      Exit Function
   End If
   Деление = x / y
End Function
...
' Вызов функции
Debug.Print Деление(10, 5) ' 2
Debug.Print Деление(10, 0) ' 0

Рекурсия. Вычисление факториала

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

Листинг 9.17. Вычисление факториала

Function Факториал(n As Long) As Long
   If n < 2 Then
      Факториал = 1
   Else
      Факториал = n * Факториал(n - 1)
   End If
End Function
...
' Вызов функции
Debug.Print Факториал(2) ' 2
Debug.Print Факториал(3) ' 6
Debug.Print Факториал(4) ' 24
Debug.Print Факториал(5) ' 120
Debug.Print Факториал(6) ' 720
Предыдущая статья Все статьи Следующая статья