Тверской государственный университет
Опубликован: 13.09.2006 | Доступ: свободный | Студентов: 3490 / 369 | Оценка: 4.65 / 4.29 | Длительность: 30:37:00
Специальности: Программист, Менеджер
Лекция 10:

Процедуры и функции

Использование именованных аргументов

В предыдущих примерах фактические параметры вызова процедуры или функции располагались в том же порядке, что и формальные параметры в ее заголовке. Это не всегда удобно, особенно если некоторые аргументы необязательны ( Optional ). VBA позволяет указывать значения аргументов в произвольном порядке, используя их имена. При этом после имени аргумента ставятся двоеточие и знак равенства, после которого помещается значение аргумента (фактический параметр). Например, вызов рассмотренной выше процедуры-функции MyFunc может выглядеть так:

Myfunc Age:= 25, Name:= "Alex", Newdate:= DateOfArrival

Удобство такого способа особенно проявляется при вызове процедур с необязательными аргументами, которые всегда помещаются в конец списка аргументов в заголовке процедуры. Пусть, например, заголовок процедуры ProcEx:

Sub ProcEx(Name As String, Optional Age As Integer, Optional City = "Москва")

Список ее аргументов включает один обязательный аргумент Name и два необязательных: Age и City, - причем для последнего задано значение по умолчанию " Москва ". Если при вызове этой процедуры второй аргумент не требуется, то при вызове, не использующем именованных параметров, сам параметр опускается, но, выделяющая его запятая, должна оставаться:

ProcEx "Оля",,"Тверь"

Вместо этого можно использовать вызов с именами аргументов:

ProcEx City:="Тверь", Name:="Оля"

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

ProcEx Name:="Оля"

в качестве значения аргумента Age в процедуру передастся 0, а в качестве аргумента City - явно заданное по умолчанию значение " Москва ".

Как процедура "узнает", передан ли ей при вызове необязательный аргумент? Для этого можно воспользоваться функцией IsMissing. Она по имени аргумента возвращает логическое значение True, когда значение аргумента не передано в процедуру, и False, если аргумент задан. Но это все работает только в том случае, если параметр имеет тип Variant. Для всех остальных типов данных полагается, что в процедуру всегда передано значение параметра, явно или неявно заданное по умолчанию. Поэтому, если такая проверка необходима, то параметр должен иметь тип Variant. Отметим также, что для массива аргументов ParamArray функция IsMissing всегда возвращает False, и для установления его пустоты нужно проверять, что верхняя граница индекса меньше нижней.

Рассмотрим функцию от двух аргументов, второй из которых необязателен:

Function TwoArgs(I As Integer, Optional X As Variant) As Variant
	If IsMissing(X) Then
		' если 2-ой аргумент отсутствует, то вернуть 1-ый.
		TwoArgs = I
	Else
		' если 2-ой аргумент есть, то вернуть их произведение
		TwoArgs = I * X
	End If
End Function

Вот результаты нескольких вызовов этой функции в окне отладки:

? TwoArgs(5,7)
 35 
? TwoArgs(5.5)
 6 
? TwoArgs(5, 5.5)
 27,5 
? TwoArgs(5, "6")
 30

Аргументы, являющиеся массивами

Аргументы процедуры могут быть массивами. Процедуре передается имя массива, а размерность массива определяется встроенными функциями LBound и UBound. Приведем пример процедуры, вычисляющей скалярное произведение векторов:

Public Function ScalarProduct(X() As Integer, Y() As Integer) As Integer
	'Вычисляет скалярное произведение двух векторов.
	'Предполагается, что границы массивов совпадают.
	
	Dim i As Integer, Sum As Integer
	Sum = 0
	For i = LBound(X) To UBound(X)
		Sum = Sum + X(i) * Y(i)
	Next i
	ScalarProduct = Sum
End Function

Оба параметра процедуры, передаваемые по ссылке, являются массивами, работа с которыми в теле процедуры не представляет затруднений, благодаря тому, что функции LBound и UBound позволяют установить границы массива по любому измерению. Приведем программу, в которой вызывается функция ScalarProduct:

Public Sub TestScalarProduct()
	Dim A(1 To 5) As Integer
	Dim B(1 To 5) As Integer
	Dim C As Variant
	Dim Res As Integer
	Dim i As Integer
	
	C = Array(1, 2, 3, 4, 5)
	For i = 1 To 5
		A(i) = C(i - 1)
	Next i
	C = Array(5, 4, 3, 2, 1)
	For i = 1 To 5
		B(i) = C(i - 1)
	Next i
	Res = ScalarProduct(A, B)
	Debug.Print Res
End Sub

Конструкция ParamArray

Иногда, когда в процедуру следует передать только один массив, для этой цели можно использовать конструкцию ParamArray. Следующая процедура PosNeg подсчитывает суммы поступлений Positive и расходов Negative, указанные в массиве Sums:

Sub PosNeg(Positive As Integer, Negative As Integer, ParamArray Sums() As Variant)
	Dim I As Integer
	Positive = 0: Negative = 0
	For I = 0 To UBound(Sums()) ' цикл по всем элементам массива
		If Sums(I) > 0 Then
			Positive = Positive + Sums(I)
		Else
			Negative = Negative - Sums(I)
		End If
	Next I
End Sub

Вызов процедуры PosNeg может иметь такой вид:

Public Sub TestPosNeg()
	Dim Incomes As Integer, Expences As Integer
	
	PosNeg Incomes, Expences, -20, 100, 25, -44, -23, -60, 120
	Debug.Print Incomes, Expences
End Sub

В результате переменная Incomes получит значение 245, а переменная Expences - 147. Заметьте, преимуществом использования массива аргументов ParamArray является возможность непосредственного перечисления элементов массива в момент вызова.

Однако такое использование массива аргументов ParamArray не исчерпывает всех его возможностей. В более сложных ситуациях передаваемые аргументы могут иметь разные типы. Мы приведем сейчас пример, в котором, во-первых, действуют объекты Office 2000, а, во-вторых, используется передача параметров через массив аргументов ParamArray.

полина есенкова
полина есенкова
Дмитрий Вологжин
Дмитрий Вологжин
Добрый день, прошел тесты с 1 по 9, 10 не сдал, стал читать лекцию и всё пройденные тесты с 1 по 9 сбросились, когда захотел пересдать 10 тест.