Переменные, аргументы и флаги. Инструкция по эксплуатации.

Собственно с чего бы начать... Этот материал в общем случае вы проходили. Многие проходили его постигая шаг за шагом, на своих или приятельских ошибках, другие проходили это менеe трагическим путем, например прочитав где-либо. Ну, и , думается мне, что есть еще начинающие, которым что-то из нижесказанного может оказаться в новинку.

Итак, переменные. все мы умеем ими пользоваться. Чего уж проще. Объявил и вперед. [Между строк - о негодяях, которые убирают из Declaration секции волшебные слова Option Explicit я вообще помолчу. Надеюсь среди вас их нет.]
Однако в самом деле есть вопросы, которые переодически приходится задавать самому себе. Например, какого типа переменную стоит обьявить.

Вот и давайте подумаем о том, что делает Бэйсик при объявлении переменной? Правильно, выделяется физический кусок памяти строго заданного размера, и на этот кусок памяти ставится указатель. Зачем вообще это знать программисту на Бэйсике, раз среда сама управляет этим процессом? Затем хотя бы, чтобы понимать, что при обьявлении разных типов переменных отъедается разный размер памяти. соответственно это влияет на "прожорливость" приложения в целом. Кстати, неправильно выбранный размер переменной, используемой , например, в длинном цикле может замедлить выполнение этого цикла. Короче, в качестве совета - если есть возможность избегать использования переменных типа Variant, то пользуйтесь этой возможностью, и обьявляйте переменные как (в порядке предпочтения)

Integer , Long , Currency, Single, Double

Операции с Currency более точно производят округления, поэтому они предпочтительны при работе с деньгами.
С целыми и длинными целыми есть одна интересная хитрость. Собственно эта хитрость встречается со всеми типами данных, просто здесь они наиболее наглядны. Как вы думаете каков будет результат выполнения следующего кода?

Dim I as Integer
Dim J as Integer
Dim RES as Long
I=100
J=400
RES = I*J
Debug.Print RES

Подумали почему так выходит? Причина в способе Бэйсика преобразовывать одни типы данных в другие. (неявное приведение типов)

Строка RES = I*J выполняется так

1. Взять ЦЕЛОЕ I
2. Взять ЦЕЛОЕ J
3. Перемножить два целых ожидая получить опять таки ЦЕЛОЕ
4. Полученноое целое положить в переменную RES преобразовав его одновременно в LONG

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

RES = СLng(I)*J

Для примера ССur(I) + J вернет результат типа Currency, попытка запихать значение в RES , которое имеет тип Long , пройдет успешно, но Бэйсик выполниет преобразование в лонг за вас. Что неплохо , но иметь в виду это надо.

Есть еще проблемы с округлением, но на эту тему, кажется можно писать кандидатскую диссертацию.

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

Следующий аспект переменных, о котором надо сазать несколько слов - это область видимости и время существования.
Особенно много я об этом говорить не буду. Понятно, что переменная обьявленная в процедуре там и видна, и не видна вне нее. На форме, например. Маленький штрих - чем меньше уровень области видимости, тем больший приоритет имеет переменная. Так три переменные с одним именем Test обьявленные в модуле, на форме и в процедуре, имеют разные области видимости. В порядке Модуль-форма-процедура. При этом внутри процедуры видна будет только переменная уровня процедуры, а на форме только уровня формы. Время жизни координируется с областью видимости. Это тоже все просто. А вот теперь вопрос - что лучше использовать - глобальную переменную или переменную уровня формы? Или даже статическую переменную уровня процедуры? Последнее надо сразу отметать - если в этом нет особенной необходимости, то статические переменные, как самые медленные, надо отвергать. Что остается, модуль и форма - чем плохи переменные уровня модуля? Только одним - в случае переноса формы в другой проект вместе с ним прийдется переносить все задействованные переменные уровня модуля. Так что, если вам необходима переменная видимая "Снаружи" формы стои подумать об обьявлении ее, как Public, Тогда, при загруженной форме вы можете получить ее значение как formName.VarName. Однако, обращение к этой переменной в случае незгруженной формы, вызовет ее загрузку. Что-же, материал для выбора у вас есть. Далее думайте сами.

Теперь аргументы. Извечная проблемма - быть или не быть, то есть ByRef или ByVal. Как передавать аргументы? Сошлюсь на давнее письмо из Ru.VisualBasic

From: Dmitry Shirokov (oes@cyberax.ru)
>Hе подскажет ли кто-нибудь знающий в чем отличие subj, когда
>паpаметpы пеpедаются (по значению или по ссылке) в пpоцедуpу
>или в функцию; и когда какое нужно пpименять для пеpедачи.
> Лучше ответить с пpостым пpимеpом.

Вот пример, отражающий главное различие между ByVal и ByRef

Private Function TestSub1(ByVal ptr As Long) As Long
ptr = ptr * 2
TestSub1 = ptr
End Function

Private Function TestSub2(ByRef ptr As Long) As Long
ptr = ptr * 2
TestSub2 = ptr
End Function

Private Sub Form_Paint()
Dim var1 As Long
var1 = 1&
Print TestSub1(var1) ' Печатает <2>
Print TestSub2(var1) ' Печатает <2>
Print TestSub1(var1) ' Печатает <4>
End Sub

Фактически функции TestSub1 и TestSub2 отличаются только способом пе-
редачи параметра,а разница в результатах их работы возникает из за того,
что при выполнении действия ptr = ptr * 2 функция 1 работает со своей
локальной переменной ptr (в которую автоматически копируется значение
параметра при входе - передача по значению), а функция 2-с переменной var1
из процедуры Form_Paint.Здесь функции передается не значение переменной,а
сама переменная под видом параметра ptr, т.е. в данном случае var1 и ptr -
это одна и та же переменная (или,как говорят,var1 и ptr ссылаются на одно
и то же место в памяти - передача по ссылке).

Что касается рекомендаций по применению - вот несколько примеров, где
может пригодиться передача параметров с помощью ByRef:

1. При написании функции (или процедуры), которая возвращает более одного
параметра;
2. При написании процедуры, которая намеренно изменяет значение входного
параметра (например меняет все символы !>);
3. Для ускорения работы программы. Данная особенность выражается тем, что
при передачи способом ByVal символьной строки, переменной пользовательского
типа или типа Variant (с массивом внутри) создается полная копия ее
содержимого, что может повлечь значительные затраты времени. При передаче
способом ByRef этого не происходит (хотя имеется одно досадное исключение -
передача текстовых строк функциям, объявленным с помощью оператора Declare).

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

В общем случае - для всех числовых типов имеет смысл использовать
ByVal - для всех остальных - ByRef либо умолчание.

Ну и последнее, о чем хотелось замолвить пару слов - это флаги. Флаги (не совсем легальный с точки зрения терминологии Бэйсика термин) это какие -то обозначатели, по сути дела, они могут иметь огранниченное чило значений, поэтому полноценной переменной не являются. Например в ходе вычислений пользователь нажал Cаncel. Программа должна быть прервана, но она не знает об этом, она продолжает считать - неплохая идея "поднять флаг" - установить значение переменной, а потом, в ходе вычислений его время от времени проверять. Относящееся к области видимости переменных одинаково хорошо подходит и для флагов. Очень полезны бывают перечисления - Enum. Перечисления - это набор констант, обьединенных в группу Например создадим Enum Week

Private Enum Week
Пнд = 1
Втрн = 2
Срд = 3
Чтвг = 4
Птнц = 5
Сбт = 6
Вскр = 7
End Enum

И обьявим переменную такого типа

Dim Test As Week

После этого переменной Test пользоваться легко и приятно. Стоит набрать
Test = Как тут же выскочит подсказка со списком констант. Кстати очень удобно передавать такую переменную как аргумент.

 


Страница сайта http://silicontaiga.ru
Оригинал находится по адресу http://silicontaiga.ru/home.asp?artId=6479