Jdi na obsah Jdi na menu
Reklama
Založte webové stránky zdarma - eStránky.cz
 


GoTo - opravdu je tak hruzostrašný ...

28. 5. 2009

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řidat komentář

Přehled komentářů

Alternativa

(Premek, 29. 7. 2009 19:54)

Jasne, i tento zapis je mozny

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].