Из чего состоит тело процедуры. Выражения

Тело процедуры состоит из операторов Dim и остальных операторов. Остальные операторы выполняются по порядку.

Из чего состоят операторы? Они могут включать в себя блоки других операторов, как это делают, например, операторы If и Do. Они могут включать в себя выражения.

Мы знаем с вами уже три вида выражений: арифметические (их значение – число), строковые (их значение – текстовая строка) и логические (они принимают одно из двух значений: True или False).

Выражение, стоящее отдельно, само по себе, встречаться не может. Выражения всегда являются частью операторов. Выражения мы встречаем справа (не слева!) от знака равенства в операторе присваивания, в условиях тех же операторов If и Do, внутри скобок при обращении к методам и функциям.

В простейшем случае выражение – это литерал:

Фрагмент Где тут выражения
a = 0
b = -7 -7
s = "Привет" "Привет"

В простом случае выражение – это переменная:

a = c c
w = s s – строковое выражение

В обычном случае выражение – это литералы и переменные, соединенные знаками арифметических и других операций. В выражения входят скобки, а также математические и другие функции:

d = a + 1 Здесь три выражения: a, 1 и a+1
w = s & "ик" Здесь три выражения: s, "ик" и s & "ик"
Debug.WriteLine(b - 3) Здесь три выражения: b, 3 и b-3
b = Len(w) Здесь два выражения: w и Len(w)
b = a * (Len(w) – Rnd()) Выражение a * (Len(w) – Rnd()) и в нем 5 выражений
If c + 9 > a Then Логическое выражение c+9>a, состоящее из двух арифметических

Функции

Философия. Мы с вами уже сталкивались со стандартными функциями (например, Len(w), Abs(c+200) и др.). Стандартная функция – это некая скрытая программа, которая принимает свои параметры, указанные в скобках, в качестве исходных данных (аргументов), что-то делает с ними и в результате получает одну величину, которая и является значением функции. Много примеров функций вы найдете в 5.4.1 и по всей книге.

Когда мы видим оператор

b = a * (Len(w) – Abs(c+200))

то говорим, что при выполнении этого оператора компьютер обращается к функциям Len и Abs. А само упоминание этих функций в тексте оператора называем обращениямик этим функциям, чтобы отличить их от объявлений функций, которые являются солидными программами для вычисления значений этих функций, только скрытыми от нас. Здесь полная аналогия с обращением к процедуре пользователя. Обращение к процедуре – это коротенький оператор, а объявление процедуры может состоять из многих строк.

Обратите внимание, что обращения к стандартным функциям встречаются обычно в выражениях. Редко кто пишет отдельные операторы такого вида:

Len(w)

Abs(c + 20)

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

b = Len(w)

Здесь все понятно: мы в дальнейшем можем использовать, переменную b, которая несет в себе вычисленную величину функции, как хотим. Или, скажем, так:

Debug.WriteLine(Abs(c + 20))

Здесь тоже от абсолютной величины польза была: мы ее напечатали.

Сейчас я хочу, чтобы мы подошли к осознанию необходимости и удобства обладания собственными функциями –функциями пользователя. Функции пользователя вы создаете тогда, когда вам недостаточно функций из библиотеки классов .NET Framework. Например, вы хотите иметь функцию, аргументами которой были бы длины двух сторон прямоугольника, а значением – периметр этого прямоугольника. Но позвольте! – скажете вы – Мы только что создали процедуру, которая делает именно это, да еще и площадь вычисляет! Зачем нам нужна еще какая-то функция? А затем, что функция в данном случае удобнее и естественнее в использовании. Вы увидите, что удобнее создать и использовать две функции: Периметр и Площадь, чем одну процедуру. И не забывайте, кстати, что единую функцию Периметр_Площадь создать нельзя, так как функция может иметь только одно значение.

Пример 1. Вспомним задачу из 11.4.1. : «Известны стороны двух прямоугольников. Нужно напечатать периметр того прямоугольника, чья площадь больше.» Приведу целиком программу решения этой задачи, но уже с использованием не процедуры, как в 11.4.1. , а функций:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim A1, B1 As Integer 'Две стороны 1 прямоугольника

Dim A2, B2 As Integer 'Две стороны 2 прямоугольника

A1 = 10 : B1 = 50

A2 = 20 : B2 = 30

If Площадь(A1, B1) > Площадь(A2, B2) Then WriteLine(Периметр(A1, B1)) _

Else WriteLine(Периметр(A2, B2))

End Sub

Function Периметр(ByVal Сторона1 As Integer, ByVal Сторона2 As Integer) As Integer

Return 2 * Сторона1 + 2 * Сторона2

End Function

Function Площадь(ByVal Сторона1 As Integer, ByVal Сторона2 As Integer) As Integer

Площадь = Сторона1 * Сторона2

End Function

Пояснения. Оператор

If Площадь(A1, B1) > Площадь(A2, B2) Then WriteLine(Периметр(A1, B1)) _

Else WriteLine(Периметр(A2, B2))

содержит в себе два обращения к функции Площадь и два обращения к функции Периметр. Он хорош своей естественностью и понятностью. Действительно, он практически повторяет условие задачи:

«ЕСЛИ площадь первого прямоугольника больше площади второго,

ТО печатай периметр первого прямоугольника,

ИНАЧЕ печатай периметр второго».

Терминология. Как же устроены наши функции? Сначала о терминологии, которая очень похожа на терминологию процедур.

Все операторы, из которых состоит функция, без заголовка и конечной строки, будем называть телом функции. А вместе с этими строками – объявлением функции. Как видите, тела наших функций очень коротенькие, всего из одного оператора. Но операторов может быть сколько угодно, как и в процедуре.

Когда VB в процессе выполнения программы натыкается на функцию Периметр, он ищет в программе объявление функции с именем Периметр и начинает выполнять тело этой функции. Этот процесс называется вызовомфункции илиобращениемк функции . Говорят также, что управление передаетсяфункции. После выполнения тела функции VB возвращается к выполнению программы. Говорят, что управление возвращается к программе. Про значение функции говорят, что функция возвращает это значение в программу.

Отличия функций от процедур. Вы видите, что объявление функции очень похоже на объявление процедуры. Но функция в отличие от процедуры обладает некоторыми свойствами переменной величины. Объявление функции отличается от объявления процедуры следующими элементами:

· В заголовке функции мы пишем не Sub (процедура), а Function(функция)

· В заголовке функции после скобок с параметрами должен быть указан тип значения функции (так как у нас это численное значение имеет смысл площади или периметра, то я выбрал в обоих случаях Integer).

· Внутри тела функции ей хотя бы раз должно быть присвоено какое-нибудь значение. Именно это значение функция и будет возвращать. Присвоение можно делать двумя способами:

· Обычным оператором присваивания, в котором слева от знака равенства стоит имя функции, как если бы это была не функция, а обычная переменная (у нас этим занимается оператор Площадь = Сторона1 * Сторона2).

· При помощи специального оператора Return(у нас этим занимается оператор Return 2 * Сторона1 + 2 * Сторона2).

· В конечной строке мы пишем не End Sub (конец процедуры), а End Function(конец функции)

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

Пример 2. Рассмотрим другой пример функции. Ее параметр (аргумент) – строка. Значение функции – та же строка, повторенная столько раз, сколько символов (букв) в исходной строке. Например, если параметр – «уж», то функция – «ужуж», параметр – «Вена», функция – «ВенаВенаВенаВена». Если длина параметра превышает 8 символов, значение функции таково – «Вы задали слишком длинное слово».

Вот программа:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim S As String

S = TextBox1.Text

TextBox1.Text = Размноженное_слово(S)

End Sub

Function Размноженное_слово(ByVal Slovo As String) As String

Dim i, Длина_слова As Integer

Длина_слова = Len(Slovo)

If Длина_слова > 8 Then

Return "Вы задали слишком длинное слово"

Else

Размноженное_слово = ""

For i = 1 To Длина_слова

Размноженное_слово = Размноженное_слово & Slovo

Next

End If

End Function

Пояснения. Здесь мы пишем в текстовом поле слово и щелчком по кнопке тут же получаем в том же текстовом поле результат – размноженное слово.

Посмотрим на объявление функции. В заголовке мы видим, что как параметр функции, так и сама функция имеют тип String. Процедуры и функции, как вы уже видели, могут содержать кроме параметров также и обычные локальные переменные (в нашем случае это i и Длина_слова). Тело функции состоит из нескольких операторов.

Механика работы этой функции проста. Переменная Размноженное_слово накапливает в себе слова, как сумматор сумму. Роль плюса играет знак &. На каждой итерации второй из двух операторов присваивания удлиняет Размноженное_слово на Slovo. А итераций столько, сколько букв в слове. «Обнуляет сумматор» оператор

Размноженное_слово = ""

Роль нуля исполняет пустая строка "" длиной в 0 символов.

Для возврата значений применяется в одном месте оператор Return и в двух местах – оператор присваивания Размноженное_слово = . . .. Не запутаемся ли? – Значение одно, операторов – три. Спрашивается, какой из этих операторов в действительности вернет значение? Чтобы ответить на этот вопрос, вам нужно знать, что

между операторами Return и присваивания, используемыми для возврата значения функции, имеется существенное различие. А именно: наткнувшись на оператор Return, компьютер выполняет его и на этом немедленно прекращает выполнение функции, возвращаясь в программу, ее вызвавшую. Ничего подобного при выполнении оператора присваивания не происходит – компьютер продолжает выполнять тело функции дальше.

Если вы внимательно разберете текст этой или любой другой функции, то увидите, что вернет значение оператор, последний по времени выполнения (а не в порядке записи). Какой именно? Все зависит от длины слова. Если оно длиннее 8 букв, то значение вернет оператор Return. Если его длина – от 1 до 8 букв, то второй из двух операторов присваивания. Если вы ничего не введете в текстовое поле, то – первый.

Обязательно прогоните программу в пошаговом режиме. Вам будет любопытно наблюдать, как постепенно удлиняется Размноженное_слово.

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

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim A1, B1, П1 As Integer 'Две стороны и периметр 1 прямоугольника

Dim A2, B2, П2 As Integer 'Две стороны и периметр 2 прямоугольника

A1 = 10 : B1 = 50

A2 = 20 : B2 = 30

If Площадь(A1, B1, П1) > Площадь(A2, B2, П2) Then WriteLine(П1) Else WriteLine(П2)

End Sub

Function Площадь(ByVal Сторона1 As Integer, ByVal Сторона2 As Integer, ByRef Периметр As Integer) _

As Integer

Площадь = Сторона1 * Сторона2

Периметр = 2 * Сторона1 + 2 * Сторона2

End Function

Что мы выиграли и что проиграли? Сэкономили две строчки кода, но пришлось вводить дополнительные переменные и параметр. А самое главное – проиграли в простоте, единообразии и понятности. Функция получилась довольно нелепая.

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

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

Dim A1, B1, П1 As Integer 'Две стороны и периметр прямоугольника

A1 = 10 : B1 = 50

Площадь(A1, B1, П1)

Debug.WriteLine(П1)

Math.Abs(-20)

End Sub

Как я уже упоминал, от площади в этом примере толк есть, а от абсолютной величины – нет.

Задание 65.

Напишите функцию с двумя строковыми параметрами. Функция должна выдать длину той строки, которая короче.

Константы

Вспомним процедуру рисования дерева из 11.2.2.:

Sub Дерево()

Dim x As Single = 200

Dim y As Single = 100

Dim Ширина_кроны As Single = 20

Dim Высота_кроны As Single = 60

Dim Длина_ствола As Single = 15

Гр.FillEllipse(Brushes.Green, x, y, Ширина_кроны, Высота_кроны)

Гр.DrawEllipse(Pens.Black, x, y, Ширина_кроны, Высота_кроны)

Гр.DrawLine(Pens.Black, x + Ширина_кроны / 2, y + Высота_кроны, _

x + Ширина_кроны / 2, y + Высота_кроны + Длина_ствола)

End Sub

При помощи пяти переменных мы можем управлять положением, размерами и формой дерева. Предположим, приходит ваш начальник, смотрит на дерево и говорит: «Хорошее дерево, особенно мне нравится ширина кроны. Приказываю, чтобы отныне все деревья, нарисованные этой процедурой, имели только такую ширину кроны и никакую другую, несмотря на дальнейшее развитие и усложнение процедуры.»

Как надежно выполнить приказ начальника? Ширина кроны задается оператором

Dim Ширина_кроны As Single = 20

Если не трогать этот оператор, можно ли быть уверенным, что ширина кроны в будущем не изменится? Нельзя, так как в будущем мы можем по забывчивости дописать в процедуру операторы типа Ширина_кроны = . . . Как бороться с забывчивостью? VB предлагает средство – так называемые константы. Константа – это переменная, которой мы задаем значение при объявлении, и которая неспособна это значение в дальнейшем менять. Чтобы отличить константу от обычной переменной, в операторе объявления мы вместо Dim пишем Const:

Const Ширина_кроны As Single = 20

Отныне, если мы попытаемся дописать в процедуру операторы, имеющие возможность изменить значение константы, типа Ширина_кроны =… , VB выдаст сообщение об ошибке.

Таким образом, при помощи объявления констант мы повышаем надежность программирования.

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

a = 1 + 0.25

b = "Амазонка"

Debug.WriteLine("Волга")

If a > 3 Then . . .

литералы это 1 0.25 "Амазонка" "Волга" 3.

Кроме упомянутых выше констант, которые вы создаете сами, существует еще большое число констант, определенных в библиотеке классов .NET Framework. Объявлять их не надо, ими можно сразу пользоваться, если знать их имена и смысл. Например, такими константами являются математические константы PI и E, входящие в класс Math. Каждая из таких констант имеет конкретное значение (например, PI = 3.14159265358979323846). Мы могли бы вместо слова PI просто писать конкретное число 3.14159265358979323846, но названия запоминаются легче и записываются короче, чем числа.

Наши рекомендации