abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
AbcLinuxu hledá autory!
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    dnes 15:22 | Zajímavý článek

    Článek na blogu APNIC vysvětluje, jak správně vytvářet a používat ASPA záznamy — podepsané objekty v RPKI, které uvádějí, kteří poskytovatelé směrování jsou pro dané autonomní číslo (ASN) oprávněni. Síťoví operátoři je mohou využít k ověřování tras BGP a k odhalování úniků tras či podvržených tras.

    vencour | Komentářů: 0
    dnes 14:33 | Nová verze

    Byla vydána (𝕏) verze 8.0.0 open source programu pro prolamování hesel hashcat (GitHub, Wikipedie). Přehled novinek v příspěvku v diskusním fóru a pdf.

    Ladislav Hagara | Komentářů: 0
    dnes 14:22 | Nová verze

    Byla vydána (𝕏, Bluesky) nová verze 2026.3 linuxové distribuce navržené pro digitální forenzní analýzu a penetrační testování Kali Linux (Wikipedie). Přehled novinek se seznamem 6 nových nástrojů v oficiálním oznámení na blogu.

    Ladislav Hagara | Komentářů: 0
    dnes 08:35 | Komunita
    Pořadatelé dalšího ročníku komunitního setkání správců nejen českých a slovenských sítí CSNOG 2027 upozorňují, Call for Abstracts pro blížící se akci (20. a 21. ledna 2027, Zlín) končí už 31. října, tedy na konci tohoto týdne.. … více »
    VSladek | Komentářů: 0
    24.10. 23:22 | Bezpečnostní upozornění

    Výzkumníci ukazují, jak mohou otevřené tunely a IPv6 Extension Headers synchronizovat pakety do krátkých provozních špiček. V kontrolovaném experimentu naměřili přes 180násobnou koncentraci paketového toku vůči průměrné rychlosti odesílání — nikoli 180násobné zvětšení objemu dat. Článek obsahuje metodiku, limity měření i mitigace pro GRE, IPIP a další tunely.

    vencour | Komentářů: 1
    24.10. 12:44 | Pozvánky

    Po velkém úspěchu prvního MobileLinux Hackdaye se vracíme do Českých Budějovic s druhým ročníkem. V pátek 30. října 2026 od 10:00 se v prostorách Jihočeské univerzity uskuteční Embedded & MobileLinux Hackday #2. Těšit se můžete na témata jako Immutable Linux na telefonech (BengalOS), U-Boot a upstream vývoj, AI optimalizace pro embedded systémy nebo otevřený hardware. Nebude chybět praktické hackování, sdílení zkušeností a možnost … více »

    lkocman | Komentářů: 1
    24.10. 00:44 | Bezpečnostní upozornění

    Dne 21. října 2026 vydal projekt Node.js bezpečnostní aktualizace opravující deset zranitelností, včetně jedné umožňující potenciální vzdálené spuštění kódu (RCE). Nejzajímavější je CVE-2026-111497, chyba dekodéru Brotli, kterou objevili výzkumníci využívající OpenAI Codex Security. Chyba je v nativním dekodéru Brotli, nikoli v samotném JavaScriptu. Speciálně vytvořený komprimovaný vstup způsobí, že dekodér zamění

    … více »
    vencour | Komentářů: 15
    23.10. 17:44 | IT novinky

    Francouzský výrobce kabelů Nexans upozornil na napjaté dodávky elektrických kabelů. Výstavba nové výrobní linky pro některé typy kabelů může trvat přibližně tři roky. Datacentra potřebují rozsáhlé nízkonapěťové a středněnapěťové rozvody. Poptávka roste současně s modernizací elektrických sítí. Někteří odběratelé proto uzavírají výrazně delší dodavatelské smlouvy [Reuters].

    vencour | Komentářů: 18
    23.10. 14:44 | Zajímavý projekt

    Představena byla (𝕏) virtuální platforma FLYBENCH FPV, která nováčky provede zapojením a konstrukcí dronů.

    Ladislav Hagara | Komentářů: 11
    23.10. 04:11 | Nová verze

    Google Chrome 156 byl prohlášen za stabilní. Přehled novinek v poznámkách k vydání. Opraveno bylo 353 bezpečnostních chyb. Vylepšeny byly také nástroje pro vývojáře.

    Ladislav Hagara | Komentářů: 0
    Které desktopové prostředí na Linuxu používáte?
     (9%)
     (7%)
     (4%)
     (21%)
     (30%)
     (9%)
     (5%)
     (2%)
     (14%)
     (20%)
    Celkem 2915 hlasů
     Komentářů: 34, poslední dnes 08:24
    Rozcestník

    Ošetřování chyb v Go

    2. 8. 2011 | Jan Mercl | Programování | 12603×

    Jedním z již dříve plánovaných (mono)témat tohoto seriálu je všechno kolem ošetřování chyb. Mezitím vyšel shodou příznivých okolností na Go blogu příspěvek člena vývojového týmu Go, Andrewa Gerranda: Error handling and Go. Určitě bych na toto téma nemohl napsat článek lepší a tak s Andrewovým vědomím, souhlasem a v (doufám) souladu s původní licencí textu (Creative Commons Attribution 3.0 License), dnes přinášíme českou verzi tohoto článku, která je jen zcela nepodstatně upraveným překladem z originálu.

    Pokud jste něco v Go programovali, tak jste se už pravděpodobně setkali s typem os.Error. Hodnoty typu os.Error v Go indikují nenormální, chybový stav. Kupříkladu funkce os.Open vrátí ne nilovou hodnotu os.Error pokud se nepodaří soubor otevřít.

    func Open(name string) (file *File, err Error)

    Níže uvedená funkce otevírá soubor voláním os.Open. Při chybě vypíšeme chybové hlášení a ukončíme program pomocí log.Fatal.

    func main() {
        f, err := os.Open("filename.ext")
        if err != nil {
            log.Fatal(err)
        }
        // proměnná f má nyní hodnotu otevřeného souboru typu *File
    }

    Už s tímto množstvím znalostí o os.Error se dá v Go udělat mnoho věcí, nicméně v dnešním článku se na os.Error podíváme podrobněji a probereme některé doporučené postupy ošetřování chyb v Go.

    Obsah

    Vše co jste kdy chtěli vědět o typu os.Error, ale báli jste se na to zeptat

    link

    os.Error je rozhraní. Hodnota typu os.Error reprezentuje jakoukoli hodnotu, která umí sama sebe popsat hodnotou typu string.

    package os
    
    type Error interface {
        String() string
    }

    Na rozhraní os.Error není nic zvláštního. Je to jen široce zaužívaná konvence.

    Nejběžnější implementací rozhraní os.Error je neexportovaný typ errorString v modulu os.

    type errorString string
    
    func (s errorString) String() string { return string(s) }

    Hodnoty typu errorString je možné vytvářet např. funkcí os.NewError. Argumentem funkce je řetězec, který je konvertován na typ errorString, který ovšem implementuje rozhraní os.Error.

    func NewError(s string) Error { return errorString(s) }

    os.NewError se dá použít třeba takto:

    func Sqrt(f float64) (float64, os.Error) {
        if f < 0 {
            return 0, os.NewError("math: odmocnina ze záporného čísla")
        }
        // implementace
    }

    Pokud zavoláme Sqrt se záporným argumentem, dostaneme ne nilovou hodnotu rozhraní os.Error (jehož konkrétní implementací je hodnota typu os.errorString). Textovou hodnotu chyby lze získat buď voláním metody rozhraní os.Error, tj. String(), nebo prostým výpisem chyby:

    f, err := Sqrt(-1)
    if err != nil {
        fmt.Println(err)
    }
    

    Modul fmt umí vypsat cokoli, co má metodu String() – a to hodnota typu os.Error splňuje.

    Správný textový souhrn kontextu chyby závisí na implementaci toho kterého chybového typu. Chyba kterou vrací os.Open má textovou podobu např. „open /etc/passwd: permission denied“ a nikoli jen „permission denied“. Naopak chyba vrácená z výše uvedené funkce Sqrt neříká nic o konkrétní hodnotě nesprávného argumentu.

    Tuto informaci můžeme přidat třeba pomocí užitečné funkce fmt.Errorf. Ta naformátuje řetězec podle stejných pravidel jako fmt.Printf a výsledek převede na os.Error použitím os.NewError.

    if f < 0 {
        return 0, fmt.Errorf("math: odmocnina ze záporného čísla %g", f)
    }
    

    V mnoha případech je fmt.Errorf zcela postačující. Avšak díky tomu, že os.Error je rozhraní, můžeme jako chybu předávat i složitější datové struktury – ty pak poskytnou volajícímu možnost prozkoumat všechny podrobnosti chyby.

    Řekněme, že náš hypotetický volající bude opět chtít získat konkrétní neplatnou hodnotu předanou funkci Sqrt. To se dá zařídit třeba definicí nového chybového typu – místo použití fmt.Errorf:

    type NegativeSqrtError float64
    
    func (f NegativeSqrtError) String() string {
        return fmt.Sprintf("math: odmocnina ze záporného čísla %g", float64(f))
    }

    V případě potřeby pak může programátor v některém místě ověřovat typ (type assertion) a nakládat s hodnotu typu NegativeSqrtError nějakým zvláštním způsobem, zatímco všechna stávající volání, která např. pouze předávají ne nilové chyby funkcím jako fmt.Println nebo log.Fatal, nebudou touto změnou nijak dotčeny.

    Další příklad – modul json definuje typ SyntaxError. Funkce json.Decode jej vrací když zjistí chybu při syntaktické analýze dat ve formátu JSON.

    type SyntaxError struct {
        msg    string // popis chyby
        Offset int64  // chyba zjištěna po přečtení 'Offset' bajtů
    }
    func (e *SyntaxError) String() string { return e.msg }

    Pole Offset se v textové podobě chybového hlášení vůbec nevyskytuje, ale programátor má nyní možnost tuto hodnotu použít pro přidání údajů o zdrojovém souboru a řádce:

    if err := dec.Decode(&val); err != nil {
        if serr, ok := err.(*json.SyntaxError); ok {
            line, col := findLine(f, serr.Offset)
            return fmt.Errorf("%s:%d:%d: %v", f.Name(), line, col, err)
        }
        return err
    }

    Uvedený kód je mírně zjednodušenou verzí části skutečného programu – projektu Camlistore.

    Rozhraní os.Error předepisuje pouze metodu String; konkrétní implementace chyby může mít i další metody. Například modul net vrací v duchu běžné konvence chyby typu os.Error, ale některé implementace chyb v tomto modulu přidávají ještě další metody, definované rozhraním net.Error.

    package net
    
    type Error interface {
        os.Error
        Timeout() bool   // Byla chyba způsobena vypršením časového limitu?
        Temporary() bool // Je chyba dočasného charakteru?
    }

    Uživatelský kód může opět ověřením typu detekovat chybu typu net.Error a následně třeba reagovat různě na dočasnou chybou sítě a trvalou. Takže např. nějaký web crawler by se v prvním případě mohl rozhodnout chvíli počkat a zkusit operaci provést znovu, zatímco při jakékoli jiné nebo neodstranitelné chybě svoji činnost ukončí.

    if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
        time.Sleep(1e9)
        continue
    }
    if err != nil {
        log.Fatal(err)
    }

    Lenost matkou pokroku: Jak si ulehčit práci při ošetřování více možných chyb

    link

    Ošetřování chyb je v Go důležité stejně jako v jiných jazycích. Návrh jazyka a uvedené zvyklosti by měly programátora vybízet k explicitním kontrolám chyb v místě jejich výskytu (v kontrastu ke konvencím některých jiných jazyků, kde se v jednom místě výjimky vyvolávají – aby se pak někdy a někde úplně jinde následně zachytily ). V některých případech to v Go může vést k většímu počtu řádek, které je potřeba napsat. Naštěstí máme po ruce pár triků, jak tento dopad minimalizovat – třeba v případě obsluhy posloupnosti několika možných chyb.

    Představme si třeba Go aplikaci v App Engine, která bude obsluhovat HTTP požadavky na záznam z datového úložiště (datastore) a výsledek bude formátovat šablonou.

    func init() {
        http.HandleFunc("/view", viewRecord)
    }
    
    func viewRecord(w http.ResponseWriter, r *http.Request) {
        c := appengine.NewContext(r)
        key := datastore.NewKey("Record", r.FormValue("id"), 0, nil)
        record := new(Record)
        if err := datastore.Get(c, key, record); err != nil {
            http.Error(w, err.String(), 500)
            return
        }
        if err := viewTemplate.Execute(w, record); err != nil {
            http.Error(w, err.String(), 500)
        }
    }

    Tato funkce ošetřuje chyby vrácené funkcemi datastore.Get a viewTemplate.Execute. V obou případech se uživateli zobrazí jednoduché chybové hlášení spolu s HTTP stavovým kódem 500 („Internal Server Error“). Zatím funkce vypadá ještě poměrně dobře, ale pokud přidáme pár dalších obslužných funkcí pro HTTP požadavky, tak rychle skončíme u mnoha kopií stále stejného kódu pro ošetření chyb.

    Nadefinováním vlastní obslužné HTTP funkce appHandler, která vrací chybu, lze takové opakování omezit:

    type appHandler func(http.ResponseWriter, *http.Request) os.Error

    Stejně tak změňme i funkci viewRecord, aby i ta vracela chybu:

    func viewRecord(w http.ResponseWriter, r *http.Request) os.Error {
        c := appengine.NewContext(r)
        key := datastore.NewKey("Record", r.FormValue("id"), 0, nil)
        record := new(Record)
        if err := datastore.Get(c, key, record); err != nil {
            return err
        }
        return viewTemplate.Execute(w, record)
    }

    To je sice jednodušší než původní verze, ale modul http neumí zacházet s funkcemi, které vracejí os.Error. Napravit to můžeme tím, že pro (funkční) typ appHandler implementujeme metodu ServeHTTP, definovanou rozhraním http.Handler:

    func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        if err := fn(w, r); err != nil {
            http.Error(w, err.String(), 500)
        }
    }

    Metoda ServeHTTP zavolá funkci fn a pokud dojde k chybě tak zobrazí uživateli chybové hlášení. Všimněte si, že přijímač metody fn je funkce – věc, kterou Go umí! Metoda vyvolá tuto funkci tak, že zavolá onen přijímač – příkaz je v tomto případě fn(w, r).

    Teď už jen postačí při registraci funkce viewRecord modulem http použít funkci Handle (místo původní HandleFunc), protože appHandler je typu http.Handler (nikoli http.HandlerFunc).

    func init() {
        http.Handle("/view", appHandler(viewRecord))
    }

    Když už máme tuto základní infrastrukturu ošetřování chyb pohromadě, tak bychom ji mohli učinit uživatelsky trochu přívětivější. Místo toho, abychom jen zobrazili textovou podobu chyby, bude možná lepší vrátit uživateli jednoduché chybové hlášení – spolu s příslušným HTTP stavovým kódem – a současně vypsat kompletní popis chyby do vývojářské konzole App Engine a trochu tím tak ulehčit programátorovi ladění.

    Toho můžeme dosáhnout deklarací struktury typu appError, která kromě pole typu os.Error bude obsahovat ještě pár dalších:

    type appError struct {
        Error os.Error
        Message string
        Code int
    }

    Dalším krokem bude úprava typu appHandler – nyní bude vracet hodnoty typu *appError:

    type appHandler func(http.ResponseWriter, *http.Request) *appError

    (Obvykle je chyba vracet konkrétní chybový typ místo hodnoty typu rozhraní os.Error. K důvodům se dostaneme v další části seriálu. V tomto případě je to ale správně, protože ServeHTTP je jediným místem, které hodnotu „vidí“ a používá její obsah.)

    Teď ještě zařídíme, aby metoda ServeHTTP, definovaná pro typ appHandler, zobrazila pole Message struktury appError, současně se správným HTTP stavovým Code a ještě vypsala Error do vývojářské konzole.

    func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        if e := fn(w, r); e != nil { // e je *appError, nikoli os.Error.
            c := appengine.NewContext(r)
            c.Errorf("%v", e.Error)
            http.Error(w, e.Message, e.Code)
        }
    }

    Jako poslední věc upravíme funkci viewRecord tak, aby vyhovovala novému „podpisu“ a aby vracela více kontextu při výskytu chyby:

    func viewRecord(w http.ResponseWriter, r *http.Request) *appError {
        c := appengine.NewContext(r)
        key := datastore.NewKey("Record", r.FormValue("id"), 0, nil)
        record := new(Record)
        if err := datastore.Get(c, key, record); err != nil {
            return &appError{err, "Record not found", 404}
        }
        if err := viewTemplate.Execute(w, record); err != nil {
            return &appError{err, "Can't display record", 500}
        }
        return nil
    }

    Tato verze funkce viewRecord má sice stejnou délku jako ta původní, nyní má ale každý případ ošetření chyby svůj specifický význam (více podrobností – kontextu) a tak poskytujeme uživateli o trochu více pohodlí.

    Tím to nekončí. Mohli bychom ošetřování chyb v naší aplikaci ještě dále vylepšovat. Několik námětů:

    • Obsluha chyby by mohla používat nějakou přívětivou HTML šablonu.
    • Výpisem trasy zásobníku by bylo možné dále ulehčit ladění – třeba podmíněně, pokud má uživatel práva správce.
    • Pro typ appError by šlo napsat konstruktor (v Go je to jen obyčejná funkce), který – opět pro účely ladění – automaticky ukládá při chybě výpis trasy zásobníku někam, kde se to bude později hodit.
    • Přidat zotavení chyb (pomocí recover) v rámci appHandler. Podrobnostmi se zabývá mj. článek Defer, Panic, and Recover, ale věnovali jsme se této problematice i v předchozích dílech seriálu.
    • Do konzole/logu vypsat úplnou chybu s poznámkou „Kritická chyba“, ale uživateli jenom prostě sdělit, že „došlo k závažné chybě“. To je uživatelsky přívětivější postup, protože zobrazovat koncovému uživateli podrobnosti chyby, kterým často nebude vůbec rozumět, je pro něj často frustrující zážitek.

    Na závěr

    link

    Korektní ošetřování chyb je podstatným požadavkem na každý dobrý program. Využitím technik popsaných v tomto článku byste měli být schopni psát spolehlivější a přitom v zápisu kratší Go programy.

    Autor: Andrew Gerrand

    (Originální text v angličtině a licence pro šíření: vizte odkazy v záhlaví této české verze.)

    Laboratoře CZ.NIC

    O autorovi překladu

    Jan Mercl, autor překladu, pracuje v Laboratořích CZ.NIC jako programátor pro výzkum a vývoj.

           

    Hodnocení: 100 %

            špatné • dobré        

    Nástroje: Tisk bez diskuse

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    Komentáře

    Vložit další komentář

    ________________ avatar 6.8.2011 03:29 ________________ | skóre: 5 | blog: _
    Rozbalit Rozbalit vše Re: Ošetřování chyb v Go
    fuj!
    ISSN 1214-1267   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.