Области видимости
В этой статье мы рассмотрим области видимости данных(переменных, массивов и
прочего). В языках программирования, обладающих мощным синтаксисом, обязательно
есть в наличии так называемые блоки Scope (ограничивающие области
видимости данных). Конечно же в разных языках для этих блоков свое имя, например
в языке СИ это скобочки {} , главное принцип работы! Язык FreeBasic не
стесняется впитывать все самое лучшее у популярных и мощных языков.
Блок
Scope выглядит так:
Scope
End Scope
Для блока не требуется никакого имени. Этот блок позволяет производить операции с своем теле, при том переменные , массивы, структуры или ваши собственные какие то типы данных, доступны только в этом блоке. Это чаще всего бывает удобно в больших проектах с кучей переменных, структур, массивов при каких то вычислениях. То есть мы не задумываясь о том: объявлены переменные или нет, в этом блоке у вас будут новые переменные, хотя имя будет схоже с уже объявленными. И можно не боятся, что эти вычисления хоть как то повлияют на другие места кода. Пример:
Dim a As Integer=55 Scope Dim a As String="Hello" ? a End Scope ? a Sleep
Запустите этот пример. У вас должно высветиться два результата 55 и ниже
Hello
А теперь уберите блок Scope и попробуйте запустить. Как видите,
компилятор не даст вам проделать такую операцию, написав примерно следующее:
переменная А уже объявлена. Да действительно, одноименные переменные в одной
области видимости можно объявить только один раз. И не важно что это за область
видимости:
Основной код
Структура
Процедура
Функция
Классовые
команды
Циклы
Логические команды If-endif , select case
и прочие
блоки...
Каждая из этих областей имеет свой собственный встроенный Scope. Но ничто вам не мешает в любой из областей видимости, размещать дополнительно, в неограниченных кол-вах свои области, как раз с помощью блока Scope. Еще один пример вложенных Scope:
Scope Dim a As String="Hello" ? a Scope Dim a As Integer=66 ? a End Scope End Scope Sleep
Как видите блоки Scope можно вкладывать друг в друга, при том без
ограничений. Блок подчищает за собой после своей работы, бережливо экономя
память, и конечно уничтожается сам как объект. Как будто и не было ни переменных
в нем, ни его самого. А теперь еще один пример, только уже со знакомыми
вам логическими операторами:
Dim a As Integer= 99 For a As Integer=1 To 2 ? a If 5*3 =15 Then Dim a As Integer=33 ? a Endif Next ? a Sleep
На этом примере четко видно. Мы объявили переменную один раз в основном
блоке, другой раз в цикле и как бы два раза в блоке If - endif . Но на
самом деле все эти переменные разные. А что касается двух раз в блоке If -
endif , то я уже писал выше: как только блок завершает свою работу, он
уничтожается. То есть проходя по циклу, каждый раз для блока If -
endif выделяется свежее место в памяти. Поэтому переменная легко
объявляется дважды.
Но есть одна хитрость для всех Scope, кроме функций, процедур и команд классов. Если в самом Scope не объявлять свои переменные, то им доступны переменные из другой области видимости:
Dim a As Integer= 99 For a=1 To 2 ? a If 5*3 =15 Then ? a Endif Next ? a Sleep
Обратили внимание на результат? А между тем нет ничего хитрого. Поскольку
в областях видимости циклов и логических операторов, нет своих переменных, они
пользуются общей. Мне например, очень нравится эта гибкость , которая была
недоступна, когда я писал на другом языке программирования. А в итоге в
проектах с общим кол-вом строк более 1000, мне приходилось писать длинные
имена переменных, либо обозначать их с цифрами, следить за именами переменных в
циклах. Это крайне неудобно! А при написании программ на FreeBasic, начиная
цикл, объявляю новую переменную для отсчета, и не боюсь, что она потом где-то в
коде создаст баг(ошибку).
Как я и сказал с функциями и процедурами такой вариант не катит. Там
"бронежелетный" Scope. Пробить такой scope может лишь переменная
объявленная как глобальная, то есть видимая везде. Но опять же, если вы в
процедуре, в функции или в Scope, объявите свою переменную с таким же именем, то
глобальная переменная ничего значить для этих блоков не будет. "Типа у нас своя
и чужие нам без надобности."
Глобальная переменная объявляется как и простая,
только добавляется дополнительно слово Shared:
Dim Shared a As Integer= 99 Sub my() ? a a+=1 End Sub my() ? a Sleep
Как видите объявляя переменную глобальной, нам не требуется даже ее
передавать в параметре процедуре. Процедура и так ее признала. А теперь
покрутите пример, обращая внимание на результат:
- попробуйте запустить его, объявив переменную а как обычную
- попробуйте объявить в процедуре переменную с таким же именем
- указать в процедуре параметр с именем 'а' в скобках и запустить процедуру с ним.
Ниже я предлагаю примеры по всем трем пунктам, но лучше, чтобы вы сами это сделали не заглядывая в готовое:
Dim a As Integer= 99 Sub my() ? a a+=1 End Sub my() ? a Sleep
Компилятор откажется компилировать, поскольку процедуре неизвестна
переменная a , точнее она не объявлена.
Dim Shared a As Integer= 99 Sub my() Dim a As Integer=4 ? a a+=1 End Sub my() ? a Sleep
В таком примере глобальная переменная не видна в процедуре, поскольку у
нее есть своя локальная
Dim Shared a As Integer= 99 Sub my(a As Integer) ? a End Sub my(77) ? a Sleep
В таком примере, как и в прошлом, глобальная переменная не видна в
процедуре, поскольку у нее есть своя локальная
И еще один пример для Scope:
Dim Shared a As Integer= 99 Scope Dim a As String="Freebasic" ? a End Scope ? a Sleep
Напишите свой пример с использованием select - case - end select и
глобальной переменной.
Для функций , процедур и блоков Scope, очень часто бывает нужным, чтобы переменная или массив находящиеся в них не уничтожились(не очищались после работы этих блоков). То есть вызвали процедуру, сделали какие-то расчеты, а результат находится в процедуре, до следующих вызовов. Для этого существует еще один тип объявленной переменной, имеющей название статическая или Static:
Sub my() Static a As Byte a+=1 ? a End Sub my() my() my() Sleep
Мы вызвали процедуру три раза и поскольку статическая переменная в
процедуре сохраняется, то результаты за счет вычислений разные. Попробуйте
вместо объявления с помощью Static, использовать в процедуре обычное объявление
с помощью Dim.
А теперь пример с блоком Scope:
Sub my() Scope Static a As Byte=66 a+=1 ? a End Scope End Sub my() my() my() Sleep
Здесь мы определили статической переменной первоначальное значение 66.
При первом обращении переменной будет присвоено это значение.
Все примеры выше, что используют переменные, так же работают и с другими типами данных. Можно объявлять как глобальные массивы, так и статические:
Глобальный массив:
Dim Shared As String Array(10)
Статический массив:
Static As String Array(10)
Глобальный массив со своим типом данных:
Type my a As Byte=66 b As Byte=55 End Type Dim Shared As my Array(10)
Статическая переменная со своим типом данных:
Type my a As Byte=66 b As Byte=55 End Type Sub Smy() Static As my ST End Sub
Думаю всех этих примеров достаточно, чтобы понять суть. В любом случае, советую каждый пример опробовать, переправлять как вам вздумается, только так вы получите настоящий опыт. Всего доброго!
содержание | назад | вперед