GoTo - opravdu je tak hruzostrašný ...
Už od mých prvních programatorských kroků mě ve všech knihách o VBA provázel strašák jménem GoTo. Ve všech knihách ve kterých jsem se pozvolna dovídal více a více o VBA, byl tento příkaz zatracován a považován za přežitek z 80 let, který výrazně zhoršuje čitelnost kódu. A není tedy divu, že se můj přístup k tomuto příkazu omezil pouze na konstrukci On Error Goto navěstí a nechápal jsem, když jsem příkaz GoTo viděl v kódu. jiného programátora. ( cožpak ten člověk nečetl všechny tyhle knihy ? )
Jak jsem už zmínil výše - a je to vlastně jediný důvod proč nepoužívat - příkaz Goto - výrazně snižuje čitelnost kódu. No, ne tak docela ...
Nejčastější důvod použití byly ( jsou ) odskoky z cyklu, návraty kodu při určitých podminkách a ve výsledku se kod opravdu stáva značně nečitelný, protože pořád někde odskakujete ( hlavně zpětné odskoky dokáži zamotat hlavu ).
Zde uvadím příklad, kde opravdu GoTo neni použit zrovna tak, aby jste jednoduše četli kod odshora dolu a věděli o čem je řeč.
Sub Cyklus_pouzivajici_GoTo()
' test zda je prvni bunka prazdna
If IsEmpty(ActiveCell) Then Exit Sub
' navesti, kde se ma vracet smycka
top:
' zobrazeni hodnoty z aktivni bunky
MsgBox ActiveCell.Value
' posunuti dolu
ActiveCell.Offset(1, 0).Select
' pokud bunka neni prazdna, opakuje smycku
If Not IsEmpty(ActiveCell) Then GoTo top
End Sub
Jedná se pouze o příklad, k nalezení na stránkách Microsoftu.
Úvod tohoto článku je napsán celý v minulém čase, z toho se dá vytušit, že jsem změnil názor na GoTo. Postupem času jsem se dostal k programování ve VB.NET, kde se pro kontrolu chyb používá konstrukce
Try
' kod kde se muze vyskytnout chyba
Catch
' pokud nastane chyba, kod prejde zde
Finally ' nepovinne
' tento kod se vykoná vzdy, at byla chyba nebo ne
Musím říct, že tato konstrukce se mi hodně líbí, všichni známe tu situaci, kdy píšete citlivý ( rozuměj náchylný na chybu ) kod a když chyba nastane tak zobrazit hlášku, vynulovat proměnné a odejít. A co když chyba nenastane? Tak zobrazit hlášku o úspešném ukončení , vynulovat proměnné a odejít. Nevidíte podobné rysy? Donedávna sem to rešil nějak takto
Sub ProcedurasChybou()
Dim objWeb As Object
Dim rngArea As Range
Dim wkbMain As Workbook
On Error GoTo ErrorHandler
Application.ScreenUpdating = False
' kod procedury
Application.ScreenUpdating = True
MsgBox "Uspesne jsme aktualizovali data"
Set objWeb = Nothing
Set rngArea = Nothing
Set wkbMain = Nothing
Exit Sub
ErrorHandler:
Application.ScreenUpdating = True
Set objWeb = Nothing
Set rngArea = Nothing
Set wkbMain = Nothing
MsgBox "Neznama chyba pri aktualizaci dat"
End Sub
Sami můžete vidět, že na dvou místech procedury řeším stejné věci. To je, návrat prostředí aplikace do původního stavu a výmaz proměnných.
Jak se tohle týka GoTo?
Jednoduše, co kdybychom si udělali ve VBA něco podobného jako Try, Catch, Finally? A nebude to ani tak těžké, podívejte se na proceduru níže
Sub ProcedurasChybouTryCatchFinally()
Dim objWeb As Object
Dim rngArea As Range
Dim wkbMain As Workbook
On Error GoTo ErrorHandler
Application.ScreenUpdating = False
' kod procedury
MsgBox "Uspesne jsme aktualizovali data"
ExitRoutine:
Application.ScreenUpdating = True
Set objWeb = Nothing
Set rngArea = Nothing
Set wkbMain = Nothing
Exit Sub
ErrorHandler:
MsgBox "Neznama chyba pri aktualizaci dat"
GoTo ExitRoutine
End Sub
Jednoduché a mocné. Přišli jsme sice o aktualizaci obrazovky před zobrazením zprávy, ale to není samozřejmě žádný problém dopsat.
Najednou se příkaz GoTo stává pomocníkem a šetří nám práci a to prestože se provádí odskok nahoru. Řekněte sami, čte se to nějak extrémě špatně?
Pojďme se podívat na jiný problém a to je čitelnost kodu s GoTo. Asi mi dáte za pravdu, že výpis kódu v úvodu tohoto článku není dvakrát čitelný. Tento přístup je opravdu ne moc dobrý a nedoporučuji ho používat. Možná si říkate, "není to tak strašné", ale v případě, že kód je obsáhlejší a odskoku je více, dá se do toho krásně zamotat.
Podívejme na proceduru která testuje podmínky a když některá z např. 5 podmínek není splněna ukončí se celá procedura. Donedávna jsem to řešil takto
Public Sub JeToCitelne_Otazka()
Dim strMetaData As String
Dim rngTemp As Range
Dim strAnalystNames As String
Dim strErrMsg As String
Dim strAnalysts() As String
Dim i As Integer
Dim intError As Integer
On Error GoTo ErrorHandler
' Zavolam nejakou funkci a na zaklade vracenych dat se rozhodnu
If Len(GetDocMetaData) = 0 Then
' a dalsi funkce
strAnalystNames = GetNodeValue(META_ANALYSTS, strMetaData, intError)
If intError > 0 Then
' a dalsi funkce
If MakeIntoArray(";", strAnalystNames, strAnalysts()) = False Then
With ActiveSheet
' spousty prikazu
End With
Else 'If MakeIntoArray(";", strAnalystNames, strAnalysts()) = False Then
strErrMsg = "Nelze nahrat data do pole." & vbCr
GoTo ErrorHandler
End If 'If MakeIntoArray(";", strAnalystNames, strAnalysts()) = False Then
Else 'If intError > 0 Then
strErrMsg = "Nelze ziskat jmeno analytika z zadanych dat" & vbCr
GoTo ErrorHandler
End If 'If intError > 0 Then
Else 'If Len(GetDocMetaData) = 0 Then
strErrMsg = "Nemohu ziskat data"
GoTo ErrorHandler
End If 'If Len(GetDocMetaData) = 0 Then
ExitFunction:
Set rngTemp = Nothing
Exit Sub
ErrorHandler:
If strErrMsg = "" Then
strErrMsg = "Chybova hlaska"
End If
GoTo ExitFunction
End Sub
Jak se Vám tento kousek kodu čte? A jak nám tady může pomoct GoTo?
Co byste řekli tomuto zápisu?
Public Sub Spravne_pouziti_GoTo()
Dim strMetaData As String
Dim rngTemp As Range
Dim strAnalystNames As String
Dim strErrMsg As String
Dim strAnalysts() As String
Dim i As Integer
Dim intError As Integer
On Error GoTo ErrorHandler
' Zavolam nejakou funkci a na zaklade vracenych dat se rozhodnu
strMetaData = GetDocMetaData
If Len(strMetaData) = 0 Then
strErrMsg = "Nemohu ziskat data"
GoTo ErrorHandler
End If
' a dalsi funkce
strAnalystNames = GetNodeValue(META_ANALYSTS, strMetaData, intError)
If intError > 0 Then
strErrMsg = "Nelze ziskat jmeno analytika z zadanych dat" & vbCr
GoTo ErrorHandler
End If
' a dalsi funkce
If MakeIntoArray(";", strAnalystNames, strAnalysts()) = False Then
strErrMsg = "Nelze nahrat data do pole." & vbCr
GoTo ErrorHandler
End If
With ActiveSheet
' spousty prikazu
End With
ExitFunction:
Set rngTemp = Nothing
Exit Sub
ErrorHandler:
If strErrMsg = "" Then
strErrMsg = "Chybova hlaska"
End If
GoTo ExitFunction
End Sub
Která ze těchto dvou procedur se Vám lépe čte?
Bohužel, už nelze nastavit menší písmo, aby se text nezalomoval, doporučuji překopírovat do klasického modulu a porovnat.
Komentáře
Přehled komentářů
Very good advice. Thanks a lot!
Who wants to write my essay https://paperwritingservicecheap.com how to write good essays in college https://essaypromaster.com
Máte pravdu,
(Martin Král, 28. 7. 2009 19:24)ale spousta programátorů by pravděpodobně použila příkaz Resume [i]LineLabel[/i].
writers needed q93ubp
(Gregorylag, 6. 4. 2023 7:24)