Řečeno slovní hříčkou, pojmy uvedené v titulku mají společného „všechno a nic“. Každý z nich je vyjádřením stavu prázdné proměnné, a to podle datového typu či kontextu.
Empty
- vyjadřuje neinicializovanou proměnnou typu Variant (její výchozí hodnotu)
- ve VBA klíčové slovo Empty, funkcí IsEmpty testujeme například prázdnou buňku
- ve VBA funkce VarType vrací 0 (vbEmpty)
- dle kontextu je za Empty považována jak nula, tak prázdný řetězec
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 36 37 38 39 40 | Sub TestEmpty() Dim a, x a = 3 'správně a = Empty 'špatně 'a = vbEmpty 'vbEmpty ... 0 (datový typ Long) 'běžně jen pro testování VarType '0 x = VarType(a) 'True x = VarType(a) = vbEmpty 'Allen Browne: 'obojí True Debug.Print Empty = 0 Debug.Print Empty = "" '-1 (True) x = Not a '1 x = a ^ 0 '0 x = a And True 'test na prázdnou buňku, True x = ActiveCell = Empty 'lépe, True x = IsEmpty(ActiveCell) End Sub |
Null (no valid data, C NULL)
http://cs.wikipedia.org/wiki/NULL
- indikuje neznámou hodnotu pro datový typ Variant
- v databázi položka pole, na níž se nevyskytují žádná data
- ve VBA klíčové slovo Null, testujeme prostřednictvím funkce IsNull
- ve VBA funkce VarType vrací 1 (vbNull)
- ve VBA Chr(0), resp. vbNullChar používán jako ukončovací znak řetězce (C NULL v programovacím jazyce C, typicky API funkce), na listu nelze zadat funkci ZNAK(0)
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | Sub TestNull() 'http://cs.wikipedia.org/wiki/NULL Dim x, y, z 'špatně 'z = vbNull 'vbNull ... 1 (datový typ Long) 'běžně jen pro testování VarType 'znak Null (datový typ String) 'odpovídá NULL v jazyce C z = Chr(0) 'ekvivalent z = vbNullChar '1 x = Len(z) 'správně z = Null '1 x = VarType(z) 'True x = VarType(z) = vbNull 'Null x = 1 + z 'y x = "y" & z 'False x = False And z 'Null v porovnání s Null nevrací True x = z = z 'True x = IsNull(z) 'bez chyby, ale pravděpodobně bez účinku ActiveCell = Null 'podobně 'ActiveCell = Chr(0) 'na listu nelze zadat ZNAK(0) Dim aPole(1 To 1) aPole(1) = Null 'funkce listu TRANSPOZICE neumí Null převádět ActiveCell = WorksheetFunction.Transpose(aPole) 'chybný test na prázdnou buňku, False x = IsNull(ActiveCell) 'správný test na prázdnou buňku, True x = IsEmpty(ActiveCell) End Sub |
Nothing
- vyjadřuje neinicializovanou (nepřiřazenou) objektovou proměnnou (její výchozí hodnotu)
- platí pro proměnné deklarované jako As Object, Workbook, Worksheet, Range, UserForm, Connection, …
- ve VBA ruší vazbu (asociaci) objektové proměnné na aktuální objekt (Set rngBunka = Nothing), čímž také uvolňuje systémové zdroje (alokovanou paměť)
- testujeme operátorem Is (rngBunka Is Nothing), tj. VBA nezná funkci IsNothing
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 36 37 38 | Sub TestNothing() Dim rngBunka As Range Dim blnRes As Boolean 'True blnRes = rngBunka Is Nothing 'přiřazení buňky A1 aktivního listu 'do objektové proměnné (typu Range) Set rngBunka = Range("A1") 'False blnRes = rngBunka Is Nothing 'ruší vazbu objektové proměnné 'na buňku A1 aktivního listu Set rngBunka = Nothing 'True blnRes = rngBunka Is Nothing 'Allen Browne: 'datový typ Variant/Empty Dim varPromenna As Variant 'nelze 'x = varPromenna Is Nothing 'dojde k přetypování na Variant/Object Set varPromenna = Nothing 'True x = varPromenna Is Nothing End Sub |
Missing
- ve VBA funkce IsMissing ověřuje, zda-li byl proceduře (funkci) předán argument (parametr musí být typu Variant, jinak budeme nuceni testovat výchozí hodnotu daného datového typu)
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 36 37 38 39 40 41 | Sub TestMissing() Call VlastniFunkce1 Call VlastniFunkce2 Call VlastniFunkce2("") End Sub Function VlastniFunkce1(Optional varPromenna As Variant) 'při volání Call VlastniFunkce 'je proměnná varPromenna typu Variant/Error 'a obsahuje hodnotu Missing Dim blnRes As Boolean 'testovat na hodnotu Missing 'lze jen proměnnu typu Variant blnRes = IsMissing(varPromenna) 'nebo blnRes = IsError(varPromenna) End Function Function VlastniFunkce2(Optional varPromenna As String) 'při volání Call VlastniFunkce2 'je proměnná varPromenna typu String 'a obsahuje prázdný řetězec coby výchozí hodnotu Dim blnRes As Boolean 'nelze testovat na Missing 'blnRes = IsMissing(varPromenna) 'True blnRes = varPromenna = vbNullString End Function |
Prázdný řetězec (null string, zero-length string, empty string)
http://en.wikipedia.org/wiki/Empty_string
- řetězec nulové délky, datový typ String neobsahující žádný znak
- nemá zastoupení v ASCII tabulce
- je-li ve VBA (nebo na listu) vyjadřován dvojicí uvozovek jdoucích bezprostředně za sebou (tj. „“, zero-length string, empty string), pak v paměti využívá 6 bitů a ukazatel na řetězec v paměti StrPtr(„“) = číslo
- ve VBA konstanta vbNullString (null string, null pointer, rychlejší při porovnávání než „“), nezabírá v paměti místo, ukazatel na řetězec v paměti StrPtr(vbNullString) = 0
- i když prázdná buňka obsahuje ve své vlastnosti Text prázdný řetězec, funkce listu JE.TEXT u ní narozdíl od skutečně obsaženého prázdného řetězce vrací NEPRAVDA
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 | Sub TestPrazdnyRetezec() Dim a, b a = "" b = vbNullString 'rozlišení "" a vbNullString 'číslo... x = StrPtr(a) '0 (datový typ Long) x = StrPtr(b) 'test na prázdný řetězec 'True x = a = "" 'lépe 'True x = a = vbNullString 'nejlépe 'True x = Len(a) = 0 End Sub |
Co je to ta inicializace?
Inicializace představuje explicitní přiřazení počáteční hodnoty do (deklarované) proměnné.
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 | Sub PrikladDeklaraceInicializace() 'VBA 'deklarace proměnné s názvem intCislo datového typu 'Integer, tj. celé číslo v rozsahu -32 768 až 32 767 'vyžadující 2 bajty v paměti Dim intCislo As Integer 'pozn. přidělování paměťového prostoru proměnným 'se říká alokace paměti 'již v tuto chvíli proměnná intCislo obsahuje nepřímo 'definovanou (implicitní) hodnotu, což je pro datový typ 'Integer nula 'inicializace, tj. přiřazení počáteční hodnoty přímo '(explicitně) intCislo = 5 'deklaraci a inicializaci současně lze ve VBA provést 'pouze u konstant nebo volitelných parametrů procedur (funkcí) 'konstanta Const dblPi As Double = 3.14159 'VB.NET 'deklaraci i inicializaci lze i u proměných 'provádět současně 'Dim intCislo As Integer = 5 End Sub |
V souladu s teorií je tedy za tu pravou inicializaci považováno přiřazení intCislo = 5. Nicméně podle mého názoru prvotní inicializaci (nastavení výchozích hodnot) u jednoduchých datových typů provádí Excel už v rámci „továrního nastavení“. tj. bezprostředně po deklaraci. U objektových proměnných je inicializace čistě na nás (a stejně tak inicializace třídy).
A jaké jsou výchozí hodnoty pro jednoduché datové typy?
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 | Sub VychoziHodnotyDatovychTypu() 'hodnota (datový typ/podtyp) 'Empty (Variant/Empty) Dim a 'totéž jako As Variant '0 (Integer) Dim b As Integer '0 (Double) Dim c As Double 'vbNullString, konstanta pro prázdný řetězec (String) Dim d As String 'Chr(0), znak pro prázdný řetězec (String) Dim e As String * 255 'Nothing (Object) Dim f As Object 'False (Boolean) Dim g As Boolean '? (Variant(), tj. pole budoucích hodnot typu Variant) Dim h() '? (String(), tj. pole budoucích hodnot typu String) Dim i() As String End Sub |
Tip 1
Je možné snadno převést Null, Empty a prázdný řetězec na nulu? Ano.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Sub NulaZNiceho() Dim a, b, c, d a = Null b = vbNullString c = Empty 'univerzální převod, výsledkem 0 d = Val("" & a) e = Val("" & b) f = Val("" & c) End Sub |
Tip 2
Je možné snadno testovat, zda-li je prázdné pole? Ano.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | Sub TestyPole() Dim Pole1(1 To 3) Dim Pole2() 'True boolPole1JePrazdne = Len(Join(Pole1, "")) = 0 Pole1(2) = "Liberec" Pole1(3) = 256 'False boolPole1JePrazdne = Len(Join(Pole1, "")) = 0 'True boolPole2JePrazdne = (Not Pole2) = True 'Array nebo ReDim Pole2 = Array(vbNullString, vbNullString) 'False boolPole2JePrazdne = (Not Pole2) = True End Sub |
Je to vše?
Bohužel, ani náhodou. Hlavní „války o nic“ se odehrávají na listu Excelu. Do bitev vstupuje skrytí buňky přímo či filtrem, formát buňky pro zneviditelnění hodnoty (vynechání sekce po sobě jdoucími středníky), skrývání nul a další lahůdky související s XML (viz třeba článek Záhada zmrazené buňky).
Prázdná buňka
Její definici jsem čas od času nucen sám přehodnotit v souvislosti s novými poznatky. V souladu s tím, co bylo napsáno výše, se obsah skutečně prázdné buňky chová jako Variant/Empty. Podle kontextu je brána jako nula (běžný výsledek prostého odkazu na buňku), prázdný řetězec nebo NEPRAVDA. Přesto vás výsledky některých funkcí listu jistě zaskočí.
U prázdné buňky převažuje numerické chování nad textovým. To je bohužel nepříjemné. Z odkazu ve vzorci obdržíme nulu, čímž Excel smaže rozdíl mezi „mít nulu“ a „nemít nic“. To v praxi znamená nerozlišovat mezi „nemít založen v bance účet“ a „nemít na existujícím účtu ani korunu“. Nebo – a to je horší – neprovádět měření versus naměřit nulovou odchylku. Do třetice příklad vypůjčený spíš z oblasti databází – odpojený elektroměr pana Kropáčka (potřebujeme přitom zachovat záznam o tom, že byl klientem naší společnosti), a paní Šebestová, která za daný měsíc neodebrala elektřinu, protože je momentálně s přítelem Machem v zahraničí.