03 - Zmienne


Podczas tej lekcji nauczymy się czym są zmienne i jak z nich korzystać. Dowiemy się również na czym polega deklaracja zmiennych i dlaczego warto ją stosować.

Stosowanie w kodzie zmiennych

Przypomnij sobie przykładowy kod z poprzedniej lekcji, który wypisywał do arkusza poszczególne potęgi dwójki i trójki:
1
2
3
4
5
6
7
8
9
10
11
12
Sub wypisywaniePoteg()
    Worksheets("Arkusz1").Cells(1, 1) = 1
    Worksheets("Arkusz1").Cells(2, 1) = 2
    Worksheets("Arkusz1").Cells(3, 1) = 4
    Worksheets("Arkusz1").Cells(4, 1) = 8
    Worksheets("Arkusz1").Cells(5, 1) = 16
    Worksheets("Arkusz2").Cells(1, 1) = 1
    Worksheets("Arkusz2").Cells(2, 1) = 3
    Worksheets("Arkusz2").Cells(3, 1) = 9
    Worksheets("Arkusz2").Cells(4, 1) = 27
    Worksheets("Arkusz2").Cells(5, 1) = 81
End Sub

Jak widzisz, w każdej linijce powyższego kodu wartość poszczególnych potęg jest obliczana w pamięci i ręcznie przypisywana do kolejnych komórek arkusza.

Oczywiście w poważnych aplikacjach taki sposób programowania nie ma racji bytu, chociażby dlatego, że bardzo łatwo się pomylić przy liczeniu czegokolwiek w pamięci. Zresztą przy większych potęgach trzeba byłoby niewątpliwie sięgnąć po kalkulator, a przecież nie po to piszemy programy, aby korzystać przy tym z kalkulatora lub obliczać coś w pamięci.

Sposobem na obejście tego problemu jest zastosowanie zmiennych.

Zmienna to taki element programu, do którego można przypisać jakąś wartość.

Po przeanalizowaniu poniższego przykładu, zrozumiesz jak działają zmienne i jak się z nich korzysta.

Najpierw zmodyfikuj kod z poprzedniej lekcji do postaci takiej, jak przedstawiono w poniższej ramce. Pod ramką z kodem znajdziesz jego szczegółową analizę.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Sub wypisywaniePoteg()
    Dim potega As Long

    potega = 1
    Worksheets("Arkusz1").Cells(1, 1) = potega

    potega = potega * 2
    Worksheets("Arkusz1").Cells(2, 1) = potega

    potega = potega * 2
    Worksheets("Arkusz1").Cells(3, 1) = potega

    potega = potega * 2
    Worksheets("Arkusz1").Cells(4, 1) = potega

    potega = potega * 2
    Worksheets("Arkusz1").Cells(5, 1) = potega

    '========================

    potega = 1
    Worksheets("Arkusz2").Cells(1, 1) = potega

    potega = potega * 3
    Worksheets("Arkusz2").Cells(2, 1) = potega

    potega = potega * 3
    Worksheets("Arkusz2").Cells(3, 1) = potega

    potega = potega * 3
    Worksheets("Arkusz2").Cells(4, 1) = potega

    potega = potega * 3
    Worksheets("Arkusz2").Cells(5, 1) = potega
End Sub

Na pierwszy rzut oka po wprowadzeniu zmiennej cała procedura wydaje się być o wiele bardziej skomplikowana, a kod znacznie dłuższy. (Kod rzeczywiście jest znacznie dłuższy, ale wynika to po części z pustych wierszy, wstawionych dla zwiększenia czytelności).

Jeżeli przyjrzysz się jednak uważniej powyższej procedurze, zauważysz, że większość linijek kodu jest do siebie bardzo podobna, a czasem wręcz identyczna (Powtarzanie kilka razy podobnych poleceń to bardzo zła praktyka, ale na razie nie posiadasz jeszcze wiedzy pozwalającej na uniknięcie tego błędu. W kolejnych lekcjach nauczysz się korzystać m.in. z funkcji i pętli, dzięki którym cała powyższa procedura zostanie skrócona do maksymalnie kilku linijek).

Pierwszą i ostatnią linijkę powyższego kodu znasz już z poprzedniej lekcji. Jest to po prostu Function" title="Jak otwierać i zamykać procedury?"> otwarcie i zamknięcie procedury.

W wierszu 2 pojawia się już jednak niespotykane dotychczas polecenie:
2
Dim potega As Long

Przedstawiona linijka kodu odpowiada za deklarację zmiennej. Termin deklaracja zmiennej oznacza poinformowanie kompilatora VBA, że w tej procedurze pojawi się zmienna o takiej nazwie i takim typie, jak podano w wierszu deklaracji.

Kompilator VBA możesz sobie wyobrazić jako nadzorcę przepływu danych w kodzie. W momencie zadeklarowania zmiennej (czyli wierszu 2) kompilator zapisuje sobie w pamięci, że w tej procedurze pojawi się zmienna potega.

Czy deklarowanie zmiennych jest konieczne?

Zasadniczo zadeklarowanie zmiennej nie jest koniecznością i procedura równie dobrze zadziałałaby, gdyby ten wiersz został pominięty. W takiej sytuacji kompilator nie wie jednak o istnieniu tej zmiennej, aż do momentu jej pojawienia się w kodzie (więc w powyższym przykładzie dopiero w linijce 4 zapisałby sobie w pamięci, że w programie istnieje zmienna potega i równocześnie dopisałby do niej wartość).

Na pierwszy rzut oka może się to wydawać wygodne - po co marnować czas na pisanie dodatkowej linijki i wcześniejsze informowanie kompilatora o zmiennych, skoro równie dobrze można tę część pominąć?

Pomijanie deklaracji zmiennych może jednak prowadzić do istotnych i trudnych do wychwycenia pomyłek!

Temat ten zostanie dokładniej omówiony w dalszej części tej lekcji.

Błędy wynijakące z braku deklaracji zmiennych są trudne do wykrycia, dlatego warto, żebyś już od początku swojej nauki programowania wyrobił w sobie nawyk deklarowania zmiennych.

Postać ogólna deklaracji zmiennej wygląda następująco:
 
Dim nazwa [As typ_zmiennej]

Słowem kluczowym odpowiedzialnym za deklarowanie zmiennej jest Dim. Po tym słowie następuje nazwa zmiennej. Jeżeli chodzi o przyjęte reguły nazewnictwa, obowiązują podobne zasady jak przy nazywaniu funkcji i procedur, omówione w poprzedniej lekcji).

Po nazwie zmiennej powinno się pojawić słowo kluczowe As, po którym zostaje określony typ zmiennej. Dostępne typy zmiennych poznasz w kolejnej lekcji, która w całości będzie poświęcona typom zmiennych.

Na potrzeby tej lekcji wprowadzimy tylko jeden typ zmiennej - Long. Jeżeli zmienna zostaje zadeklarowana z typem Long, oznacza to, że może ona jako swoją wartość przyjmować liczby całkowite z zakresu od -2 147 483 648 do 2 147 483 647.

Określenie typu zmiennych może zostać pominięte, jednak w takiej sytuacji zmienna zostaje domyślnie zadeklarowana jako zmienna typu Variant, co, jak dowiesz się w kolejnej lekcji, nie jest dobrą praktyką.

Język VBA umożliwia również deklarowanie kilku zmiennych w jednej linijce, co zostało przedstawione w poniższej ramce z kodem:
 
Dim zmienna1 As Long, zmienna2 As Long, zmienna3 As Long

Chociaż wszystkie zadeklarowane w tej linijce zmienne posiadają ten sam typ danych - Long - zwróć uwagę, że do każdej z nich został on oddzielnie przypisany.

Gdyby powyższa deklaracja zmiennych została zapisana w takiej postaci:
 
Dim zmienna1, zmienna2, zmienna3 As Long

to wbrew pozorom, zmienne zmienna1 i zmienna2 nie posiadałyby typu Long.
Każde przypisanie typu dotyczy tylko tej zmiennej, przy której bezpośrednio się znajduje (w tym przypadku zmienna3), a nie całej linijki. W rzeczywistości do zmiennych zmienna1 oraz zmienna2 nie byłby więc przypisany żaden typ danych i, jak wspomniałem przed momentem, otrzymałyby one domyślny typ danych Variant, czego zdecydowanie powinno się unikać.

W jednej procedurze nie mogą być zadeklarowane dwie zmienne o takiej samej nazwie.

Wróćmy do analizy przedstawionego wcześniej kodu.

Kiedy wykonywanie kodu dociera do wiersza 4, w programie jest już zadeklarowana zmienna typu liczbowego o nazwie potega (została zadeklarowana w wierszu 3). Na razie jednak kompilator otrzymał tylko informację o istnieniu takiej zmiennej, nie przechowuje ona jeszcze żadnej wartości (a w zasadzie przechowuje wartość domyślną, czyli 0). Taki stan rzeczy nie potrwa jednak długo, bo już w czwartym wierszu kodu zostaje do niej przypisana wartość:
4
potega = 1

Tak jak zostało przed chwilę wspomniane, w tej linijce kodu do zmiennej potega zostaje przypisana wartość 1. Kompilator zapisuje więc w swojej pamięci przy zmiennej potega wartość 1.
Od tej pory, kiedy kompilator napotka w kodzie zmienną potega, będzie ją interpretował jako liczbę 1, tak długo, aż do tej zmiennej zostanie przypisana jakaś inna wartość.

Jak więc widzisz, przypisywanie wartości do zmiennej jest bardzo proste. Wystarczy napisać nazwę zmiennej, postawić znak równości =, a następnie napisać wartość, jaka ma zostać do tej zmiennej przypisana.

W wierszu 5 znajduje się znana Ci już z poprzedniej lekcji operacja wyprintowania wartości do komórki arkusza:
5
Worksheets("Arkusz1").Cells(1, 1) = potega

W tej operacji, w komórce A1 arkusza Arkusz1 zostaje wyświetlona wartość znajdująca się po znaku równości. Zwróć jednak uwagę, że tym razem po znaku równości nie występuje liczba, lecz nazwa zmiennej. Na pierwszy rzut oka mogłoby się wydawać, że kompilator VBA wypisze w arkuszu tekst potega. Tak się jednak nie stanie.

Pomiędzy nazwami zmiennych, a tekstami istnieje zasadnicza różnica w zapisie i interpretacji. Występujący w kodzie tekst można rozpoznać po tym, że jest ujęty w cudzysłów. Nazwy zmiennych są natomiast zapisane bez cudzysłowia.

Aby w powyższym przykładzie w arkuszu pojawił się napis potega, tekst ten musiałby być ujęty w kodzie w cudzysłów, tak jak poniżej:
 
Worksheets("Arkusz1").Cells(1, 1) = "potega"

W naszym przykładzie słowo potega znajduje się bez cudzysłowia, w związku z czym oznacza odniesienie do zmiennej o takiej właśnie nazwie. Jak już wcześniej wspomniałem, kompilator interpretuje zmienną jako wartość, która jest w tej zmiennej aktualnie przechowywana. Zmienna potega aktualnie przechowuje wartość 1, która została do niej przypisana w wierszu 4, dlatego też wyświetlenie w komórce A1 zmiennej potega jest równoznaczne z wyświetleniem w niej liczby 1.

W kolejnym wierszu arkusza ma zostać wyświetlona kolejna potęga dwójki. Dlatego też w linii 7 kodu:
7
potega = potega * 2

zmienna potega zostaje pomnożona przez 2. Ponieważ dotychczas zmienna ta przechowywała wartość 1, teraz przyjmie wartość 2.

W kolejnych wierszach (8-18), wartość zmiennej potega jest na przemian wyświetlana w arkuszu i mnożona przez 2, tak by uzyskać kolejną potęgę dwójki.

Po wyświetleniu pięciu kolejnych potęg dwójki przyszedł czas na zajęcie się potęgami liczby 3. Zwróć uwagę, że zmienna potega posiada w tym momencie wartość 16, dlatego aby przygotować ją na przechowywanie wartości poszczególnych potęg trójki, należy zresetować jej wartość do liczby 1 (dzieje się tak w wierszu 19).

W kolejnych wierszach kodu, wartość zmiennej potega jest na przemian wyświetlana w arkuszu i mnożona przez 3, aby uzyskać kolejne potęgi trójki (a więc operacje analogiczne do tych, omówionych przed chwilą przy okazji tworzenia i wyświetlania kolejnych potęg dwójki).

Konsekwencje niedeklarowania zmiennych

Przy okazji omawiania kodu przedstawionego na początku lekcji, wspomniałem o niebezpieczeństwach wynikających z niedeklarowania zmiennych.

Przeanalizuj teraz poniższy kod, który na pierwszy rzut oka niczym nie różni się od tego, który został przed chwilą omówiony.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Sub wypisywaniePoteg()
    Dim potega As Long

    potega = 1
    Worksheets("Arkusz1").Cells(1, 1) = potega

    potega = potega * 2
    Worksheets("Arkusz1").Cells(2, 1) = potega

    potega = ptoega * 2
    Worksheets("Arkusz1").Cells(3, 1) = potega

    potega = potega * 2
    Worksheets("Arkusz1").Cells(4, 1) = potega

    potega = potega * 2
    Worksheets("Arkusz1").Cells(5, 1) = potega
End Sub

Jeżeli jednak przyjrzysz się uważnie temu fragmentowi kodu, zauważysz, że w linijce 10 zamiast zmiennej potega, wpisano ptoega.

Co dzieje się w takiej sytuacji?

W drugim wierszu tego kodu kompilator napotyka na deklarację zmiennej potega, zapisuje ją więc w swojej pamięci, a w kolejnym wierszu (4) przypisuje do niej wartość 1.

W następnych linijkach (5-9) wszystko odbywa się dokładnie tak, jak w omówionym wcześniej przykładzie - kompilator na przemian przypisuje do zmiennej potega wartość działania potega * 2, a potem wyświetla wartość tej zmiennej w arkuszu.

Jednak w kolejnej linijce (10) sytuacja się komplikuje. Otóż kompilator otrzymuje informację, że ma przypisać do zmiennej potega nie jej wartość pomnożoną razy dwa, lecz wartość zmiennej ptoega pomnożoną przez dwa.

Dla każdej osoby czytającej ten kod byłoby oczywiste, że chodzi o zmienną potega i jest to po prostu zwykła literówka. Komputer jednak nie jest tak bystry i traktuje ją jako zupełnie nową zmienną. Stwierdza więc, że w swojej pamięci nie ma jeszcze zmiennej o nazwie ptoega, dlatego dopisuje ją do listy występujących w programie zmiennych (tak jak wspomniano wcześniej w tej lekcji - jeżeli kompilator napotka na zmienną, która nie była zadeklarowana, sam ją sobie automatycznie deklaruje).

Zwróć uwagę, że zmienna ta dopiero co pojawiła się w programie i nie przypisano do niej jeszcze żadnej wartości (ma więc domyślną wartość - 0). Tak więc zgodnie z tą instrukcją:
10
potega = ptoega * 2

kompilator wykona działanie 0*2, a wynik (0) przypisze do zmiennej potega.

Zmienna potega przyjmie więc po tej operacji wartość 0, a przecież celem było przypisanie do niej kolejnej potęgi dwójki - czyli 4! I mimo, że w dalszej części kodu wszystko jest już w porządku, to od tego momentu wykonywane przez to makro czynności będą kompletnie różne od pierwotnych założeń.

Wystarczyła więc mała literówka aby sprawić, że makro działa kompletnie inaczej niż powinno, a tym samym staje się zupełnie bezużyteczne. Oczywiście jest to bardzo uproszczony przykład, jednak w przyszłości, kiedy będziesz tworzył bardziej rozbudowane aplikacje taki mały błąd może zapewnić Tobie kilka nieprzespanych nocy spędzonych na poszukiwaniu źródła błędu.

Polecenie Option Explicit

Istnieje bardzo łatwy sposób pozwalający uniknąć błędów wynikających z niedeklarowania zmiennych, opisanych w poprzednim podrozdziale. Jest nim wymuszanie deklarowania zmiennych poprzez zastosowanie polecenia Option Explicit.

Polecenie to musi być umieszczone na samej górze edytora VBA. Jego rolą jest niedopuszczanie do korzystania w programach ze zmiennych, które nie zostały wcześniej zadeklarowane.

Jeżeli do powyższego kodu (tego z literówką) dopiszesz na górze edytora polecenie Option Explicit i spróbujesz uruchomić makro, na ekranie pojawi się komunikat o błędzie, informujący o tym, że w programie znajduje się zmienna, która nie została wcześniej zadeklarowana, a dodatkowo nazwa tej zmiennej zostanie podświetlona w kodzie, tak jak to zostało pokazane na poniższym rysunku.

Błąd niezadeklarowania zmiennej

W takiej sytuacji od razu widzisz, że pomyliłeś się przy wpisywaniu nazwy zmiennej i w którym miejscu kodu to nastąpiło.

Kolejną dobrą wiadomością jest to, że edytor VBA umożliwia automatyczne dopisywanie polecenia Option Explicit w każdym nowo dodawanym module, tak abyś nie musiał się o to troszczyć i marnować czasu na każdorazowe jego wpisywanie.

Aby ustawić automatyczne dodawanie polecenia Option Explicit wybierz z paska menu edytora VBA opcję:
  • Tools
  • Options...

Uruchamianie okna opcji edytora VBA

W oknie, które pojawi się na ekranie zaznacz opcję Require Variable Declaration.

Wymuszanie deklarowania zmiennych

Dodaj teraz do pliku nowy moduł. Zauważ, że nowy moduł dodał się już z wpisanym u góry poleceniem Option Explicit.

Pamiętaj, aby zawsze w każdym module korzystać z polecenia Option Explicit!

Najlepiej włącz sobie jego automatyczne dodawanie i nigdy już nie zmieniaj tego ustawienia.