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

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

Вызовы процедур и функций

Вызовы процедур Sub

Вызов обычной процедуры Sub из другой процедуры можно оформить по-разному. Первый способ:

имя список-фактических-параметров

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

Может оказаться, что в одном проекте несколько модулей содержат процедуры с одинаковыми именами. Для различения этих процедур нужно при их вызове указывать имя процедуры через точку после имени модуля, в котором она определена. Например, если каждый из двух модулей Mod1 и Mod2 содержит определение процедуры ReadData, а в процедуре MyProc нужно воспользоваться процедурой из Mod2, этот вызов имеет вид:

Sub Myproc()
...
	Mod2.ReadData
...
End Sub

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

MyBooks.Mod2.ReadData

Второй способ вызова процедур связан с использованием оператора Call. В этом случае вызов процедуры выглядит так:

Call имя(список-фактических-параметров)

Обратите внимание на то, что в этом случае список-фактических-параметров заключен в круглые скобки, а в первом случае - нет. Попытка вызывать процедуру без оператора Call, но с заданием круглых скобок является источником синтаксических ошибок особенно для разработчиков с большим опытом программирования на Паскале или С, где списки параметров всегда заключаются в скобки. Следует обратить внимание на одну важную и, пожалуй, неприятную особенность вызова процедур VBA. Если процедура VBA имеет только один параметр, то она может быть вызвана без оператора Call и с использованием круглых скобок, не сообщая об ошибке вызова. Это было бы не так страшно, если бы возвращался правильный результат. К сожалению, это не так, проиллюстрируем сказанное примером:

Public Sub MyInc(ByRef X As Integer)
	X = X + 1
End Sub

Public Sub TestInc()
	Dim X As Integer
	X = 1
	'Вызов процедуры с параметром, заключенным в скобки,
	'синтаксически допустим, но работает не корректно!
	MyInc (X)
	Debug.Print X
	
	'Корректный вызов
	MyInc X
	Debug.Print X
	
	'Это тоже корректный вызов
	Call MyInc(X)
	Debug.Print X
 
End Sub

Вот результаты ее работы:

1 
2 
3

Хотя при первом вызове процедура нормально вызывается и увеличивает значение результата, но по завершении ее работы значение аргумента не изменяется. В этой ситуации не действует описатель ByRef, вызов идет так, будто параметр описан с описателем ByVal.

Если же процедура имеет более одного параметра, то попытка вызвать ее, заключив параметры в круглые скобки и не предварив этот вызов ключевым словом Call, приводит к синтаксической ошибке. Вот простой пример:

Public Sub SumXY(ByVal X As Integer, ByVal Y As Integer, ByRef Z As Integer)
	Z = X + Y
End Sub

Public Sub TestSumXY()
 Dim a As Integer, b As Integer, c As Integer
 a = 3: b = 5
 'SumXY (a, b, c)	'Синтаксическая ошибка
 SumXY a, b, c
 Debug.Print c
 
End Sub

В этом примере некорректный вызов процедуры SumXY будет обнаружен на этапе проверки синтаксиса.

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

Пусть, например, процедура CompVal c 4 аргументами, которая в зависимости от положительности z возвращает в переменной y либо увеличенное, либо уменьшенное на 100 значение x и сообщает об этом в строковой переменной w, определена следующим образом.

Sub CompVal(ByVal x As Single, ByRef y As Single, _
	ByVal z As Integer, ByRef w As String)
	
	If z > 0 Then		' увеличение
		y = x + 100
		w = "increase"
	Else			' уменьшение
		y = x - 100
		w = "decrease"
	End If
End Sub

Рассмотрим процедуру TestCompVal, в которой несколько раз вызывается процедура CompVal:

Sub TestCompVal()
	Dim a As Single
	Dim b As Single
	Dim n As Integer
	Dim S As String
	
	n = 5: a = 7.4	' значения параметров
	CompVal a, b, n, S		' 1-ый вызов
	Debug.Print b, S
	
	CompVal 7.4, b, 5, S ' 2-ой вызов
	Debug.Print b, S
	
	CompVal 0, 0, 0, S ' 3-ий вызов
	Debug.Print b, S
	
	CompVal 0, 0, 0, "В чем дело?" ' 4-ый вызов
	Debug.Print b, S
End Sub

В результате выполнения этой процедуры будут напечатаны следующие результаты:

107,4		increase
107,4		increase
107,4		decrease
107,4		decrease

Первые два вызова корректны. Следующие два вызова хотя и допустимы в языке VBA, но приводят к тому, что параметры, переданные по ссылке, не меняют своих значений в ходе выполнения процедуры и, по существу, вызов ByRef по умолчанию заменяется вызовом ByVal. Конечно, было бы лучше, если бы эта программа выдавала ошибки на этапе проверки синтаксиса.

Вызовы функций

Оформление вызова функции зависит от того, требуется ли использовать ее значение в вызывающей процедуре. Если Вы хотите передать вычисляемое функцией значение в переменную или применить его в выражении правой части оператора присвоения, то вызов пользовательской функции имеет тот же вид, что и вызов встроенной функции, например, sin(x). При вызове указывается имя функции, а после него идет заключенный в круглые скобки список фактических параметров. Например, если заголовок функции MyFunc:

Func Myfunc(Name As String, Age As Integer, Newdate As Date) As Integer

использовать ее значение можно с помощью вызовов:

val= Myfunc("Alex",25, "10/04/97")

или

x = sqrt(Myfunc("Alex",25, "10/04/97")) + x

Если же значение, вычисляемое функцией, нас не интересует и нужно воспользоваться лишь ее побочными эффектами, вызов функции может иметь ту же форму, что и вызов процедуры Sub. Например:

Myfunc "Alex",I, "10/04/97"

или:

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