Hlavní navigace

Serializace a deserializace datových struktur v programovacím jazyce Go

Pavel Tišnovský

Dnešní článek je věnován problematice serializace a deserializace datových struktur za účelem jejich uložení či poslání do jiné služby. Kromě běžných textových formátů typu JSON a XML je k dispozici i několik formátů binárních.

Doba čtení: 50 minut

Sdílet

11. Vylepšení předchozích příkladů

12. Serializace jedné struktury jak do JSONu, tak i do XML – problematika anotačních řetězců

13. Binární formáty a programovací jazyk Go

14. Formát gob

15. Serializace datové struktury do formátu gob

16. Formát CBOR (Concise Binary Object Representation)

17. Serializace dat do formátu BSON

18. Deserializace dat z formátu BSON

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Serializace a deserializace datových struktur v programovacím jazyce Go

V dnešní části seriálu o programovacím jazyku Go se zaměříme na popis způsobů použití různých formátů určených pro serializaci a deserializaci dat s jejich případným přenosem do jiné aplikace či služby (přenosem se myslí jak lokální komunikace, tak i přenos do služby běžící na jiném počítači). Již dříve jsme se ve stručnosti seznámili s využitím formátu JSON a nepřímo taktéž s formátem TOML používaným typicky pro konfigurační soubory (a mnohem méně často pro rozsáhlejší data). V případě JSONu se jedná o poměrně důležitý formát, protože JSON (a samozřejmě též XML) se v současnosti používá v mnoha webových službách a i když stále vznikají a jsou postupně adaptovány další formáty, ať již textové (YAML, edn) či binární (BSON, B-JSON, Smile, Protocol-Buffers), CBOR atd., je velmi pravděpodobné, že se JSON bude i nadále poměrně masivně využívat. Nicméně pochopitelně existují situace, v nichž je vhodné textový a relativně neúsporný JSON nahradit právě nějakým binárním formátem.

Některé metody serializace a deserializace datových struktur jsou implementovány přímo ve standardních knihovnách programovacího jazyka Go; další metody (resp. přesněji řečeno formáty) však již vyžadují instalaci zvláštní knihovny, popř. vlastní implementaci daného formátu. Nejdříve se zaměříme na ty formáty, které jsou podporovány bez nutnosti instalace dalších balíčků a posléze si ukážeme i některé přídavné balíčky pro ty nejzajímavější popř. nejpoužívanější formáty.

2. Rozhraní s předpisem metod pro serializaci a deserializaci dat

Základní rozhraní pro serializaci a deserializaci datových struktur jsou definována ve standardním balíčku encoding, jehož dokumentaci je možné nalézt na adrese https://golang.org/pkg/encoding/. Každé z rozhraní předepisuje – jak je ostatně v jazyce Go zvykem – pouze jednu metodu. Jakýkoli objekt, který je schopen své serializace či deserializace může tyto metody obsahovat:

# Rozhraní Signatura metody
1 TextMarshaler MarshalText() (text []byte, err error)
2 TextUnmarshaler UnmarshalText(text []byte) error
3 BinaryMarshaler MarshalBinary() (data []byte, err error)
4 BinaryUnmarshaler UnmarshalBinary(data []byte) error

Typické je, že při serializaci (marshalingu) je výsledkem řez bajtů a nikoli řetězec (ve smyslu jazyka Go). Podobně při deserialiaci (umarshalingu) je zdrojem dat parametr typu řez bajtů. Díky tomu jsme odstíněni od problematiky kódování znaků ve „skutečných“ textových řetězcích.

Poznámka: připomeňme si, že v jazyce Go není zapotřebí rozhraní explicitně implementovat (implement) tak, jak je tomu například v Javě. Plně postačuje, aby nějaký datový typ obsahoval příslušnou metodu. Potom říkáme, že tento typ rozhraní vyhovuje (satisfy).

3. Krátké zopakování – práce s formátem JSON

Před popisem dalších metod serializace a deserializace datových struktur si krátce zopakujme, jakým způsobem je ve standardní knihovně programovacího jazyka Go podporován formát JSON. Tento formát je dnes široce rozšířen a používá se jak pro ukládání konfigurací, specifikaci schématu v OpenAPI (vedle YAMLu), uložení konfigurace dashboardu v Grafaně atd., tak – a to možná především – ve webových službách a aplikacích pro přenos strukturovaných dat. Jedná se o formát, jehož syntaxe a sémantika je odvozená od JavaScriptu, s čímž je nutné počítat, protože ne všechny knihovny například umožňují, aby se v klíčích objevovaly pomlčky či jiné „podivné“ znaky, i když to teoreticky formát JSON umožňuje.

Podívejme se na příklad služby vracející dokument reprezentovaný ve formátu JSON (tuto službu můžete použít pro testování apod.):

$ curl http://httpbin.org/json
 
{
  "slideshow": {
    "author": "Yours Truly",
    "date": "date of publication",
    "slides": [
      {
        "title": "Wake up to WonderWidgets!",
        "type": "all"
      },
      {
        "items": [
          "Why <em>WonderWidgets</em> are great",
          "Who <em>buys</em> WonderWidgets"
        ],
        "title": "Overview",
        "type": "all"
      }
    ],
    "title": "Sample Slide Show"
  }
}

Formát JSON umožňuje uložení a tím pádem i přenos jediné (nijak nepojmenované) hodnoty. Podporovány jsou přitom hodnoty, které můžeme zařadit do šesti kategorií (viz též příslušná část graficky vyjádřené syntaxe formátu JSON):

# Hodnota Stručný popis
1 string řetězec (s plnou podporou Unicode)
2 number celé číslo, popř. hodnota typu double
3 object ve skutečnosti se jedná o asociativní pole (mapu), viz poznámka v úvodní kapitole
4 array pole, ovšem v JSONu nemusí mít všechny prvky pole stejný typ
5 true, false pravdivostní hodnota
6 null prázdná hodnota
Poznámka: díky tomu, že onou jedinou hodnotou může být pole či objekt, lze ve skutečnosti pracovat i s rozsáhlými a složitě strukturovanými daty.

Pro převod libovolného typu (přesněji řečeno hodnoty libovolného typu) do JSONu se používá funkce nazvaná Marshal, kterou nalezneme v balíčku encoding/json:

func Marshal(v interface{}) ([]byte, error)

Povšimněte si, že tato funkce skutečně akceptuje hodnotu libovolného typu, protože prázdné rozhraní implementuje (zcela automaticky!) každý datový typ (s tímto zajímavým konceptem „univerzálního datového typu“ se ještě několikrát setkáme, zejména v rozhraních mezi Go a dalšími systémy). Návratovou hodnotou je sekvence bajtů (nikoli řetězec!) a popř. i struktura reprezentující chybový stav, pokud k chybě skutečně došlo. V opačném případě se ve druhé návratové hodnotě funkce Marshal vrací nil, jak jsme ostatně zvyklí ze všech podobně koncipovaných funkcí.

V typických zdrojových kódech se tedy setkáme s tímto idiomatickým zápisem:

json_bytes, err := json.Marshal(a)
 
if err != nil {
        log.Fatal(err)
}
...
...
...

4. Některá úskalí převodu hodnot do formátu JSON

V některých případech, například při přenosu výsledků z různých simulací, měření, výpočtů apod. je nutné pracovat s celočíselnými hodnotami, popř. s hodnotami s plovoucí řádovou čárkou. A právě zde můžeme narazit na různá úskalí, které se týkají speciálních hodnot typu +Inf, -Inf (kladné a záporné nekonečno) a pochopitelně taktéž NaN (výsledkem nějaké operace není skutečné číslo, výsledek nelze vyjádřit atd.). Nejprve se podívejme na serializaci běžných hodnot s plovoucí řádovou čárkou. Podporován by měl být rozsah i přesnost odpovídající typu double, resp. v programovacím jazyku Go typu float64:

package main
 
import (
        "encoding/json"
        "fmt"
)
 
func main() {
        var a float64 = 0.0
        var b float64 = 1e10
        var c float64 = 1e100
        var d float64 = 2.3e-50
 
        var jsonOutput []byte
 
        jsonOutput, _ = json.Marshal(a)
        fmt.Println(string(jsonOutput))
 
        jsonOutput, _ = json.Marshal(b)
        fmt.Println(string(jsonOutput))
 
        jsonOutput, _ = json.Marshal(c)
        fmt.Println(string(jsonOutput))
 
        jsonOutput, _ = json.Marshal(d)
        fmt.Println(string(jsonOutput))
}

V tomto případě nedochází k chybám (ostatně chybové hodnoty zcela ignorujeme) a serializace do JSONu vypadá následovně:

0
10000000000
1e+100
2.3e-50

Ovšem u výše uvedených speciálních hodnot dochází k problémům, což je zmíněno například na Stack Overflow. Můžeme se o tom přesvědčit nepatrnou úpravou předchozího příkladu:

package main
 
import (
        "encoding/json"
        "fmt"
        "math"
)
 
func main() {
        var a float64 = -0.0
        var b float64 = math.NaN()
        var c float64 = -math.NaN()
        var d float64 = math.Inf(1)
        var e float64 = math.Inf(-1)
 
        var jsonOutput []byte
 
        jsonOutput, _ = json.Marshal(a)
        fmt.Println(string(jsonOutput))
 
        jsonOutput, _ = json.Marshal(b)
        fmt.Println(string(jsonOutput))
 
        jsonOutput, _ = json.Marshal(c)
        fmt.Println(string(jsonOutput))
 
        jsonOutput, _ = json.Marshal(d)
        fmt.Println(string(jsonOutput))
 
        jsonOutput, _ = json.Marshal(e)
        fmt.Println(string(jsonOutput))
}

Tentokrát se zdá, že serializace do formátu JSON vrátila pouze prázdné řetězce:

0
 
 
 
 

Ovšem skutečnost je jiná, protože balíček encoding/json hlídá, které hodnoty lze převést a které nikoli. Musíme ovšem naši aplikaci naprogramovat korektně, tj. v tomto konkrétním případě reagovat na všechny chybové stavy:

package main
 
import (
        "encoding/json"
        "fmt"
        "math"
)
 
func main() {
        var a float64 = -0.0
        var b float64 = math.NaN()
        var c float64 = -math.NaN()
        var d float64 = math.Inf(1)
        var e float64 = math.Inf(-1)
 
        var jsonOutput []byte
        var err error
 
        jsonOutput, err = json.Marshal(a)
        fmt.Println(err, string(jsonOutput))
 
        jsonOutput, err = json.Marshal(b)
        fmt.Println(err, string(jsonOutput))
 
        jsonOutput, err = json.Marshal(c)
        fmt.Println(err, string(jsonOutput))
 
        jsonOutput, err = json.Marshal(d)
        fmt.Println(err, string(jsonOutput))
 
        jsonOutput, err = json.Marshal(e)
        fmt.Println(err, string(jsonOutput))
}

Nyní již bude po spuštění příkladu patrné, že došlo k chybám při serializaci speciálních hodnot:

 0
json: unsupported value: NaN
json: unsupported value: NaN
json: unsupported value: +Inf
json: unsupported value: -Inf

Ještě si ukažme, jakým způsobem je možné do JSONu uložit pole s prvky různých typů, včetně dvojrozměrných polí (což v JSONu není nic jiného, než pole polí):

package main
 
import (
        "encoding/json"
        "fmt"
)
 
func main() {
        var a1 [10]byte
        var a2 [10]int32
        a3 := [10]int32{1, 10, 2, 9, 3, 8, 4, 7, 5, 6}
        a4 := []string{"www", "root", "cz"}
        a5 := []interface{}{1, "root", 3.1415, true, []int{1, 2, 3, 4}}
        matice := [4][3]float32{
                {1, 2, 3},
                {4, 5, 6},
                {7, 8, 9},
                {0, -1, 0},
        }
 
        a1_json, _ := json.Marshal(a1)
        fmt.Println(string(a1_json))
 
        a2_json, _ := json.Marshal(a2)
        fmt.Println(string(a2_json))
 
        a3_json, _ := json.Marshal(a3)
        fmt.Println(string(a3_json))
 
        a4_json, _ := json.Marshal(a4)
        fmt.Println(string(a4_json))
 
        a5_json, _ := json.Marshal(a5)
        fmt.Println(string(a5_json))
 
        matice_json, _ := json.Marshal(matice)
        fmt.Println(string(matice_json))
}

Výsledky budou vypadat následovně:

[0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0]
[1,10,2,9,3,8,4,7,5,6]
["www","root","cz"]
[1,"root",3.1415,true,[1,2,3,4]]
[[1,2,3],[4,5,6],[7,8,9],[0,-1,0]]
Poznámka: zajímavé je především pole (resp. přesněji řečeno řez s pohledem na pole) a5, protože tato datová struktura může obsahovat libovolnou hodnotu programovacího jazyka Go, a to z toho důvodu, že prázdné rozhraní (bez signatur metod) je implementováno jakýmkoli datovým typem.

5. Serializace dat do formátu XML

Ve druhé části článku si ukážeme způsoby serializace dat (tedy prakticky libovolné datové struktury) do formátu XML. Zcela nejjednodušší demonstrační příklad, v němž se pokusíme serializovat hodnoty typu User1 a User2, bude vypadat následovně:

package main
 
import (
        "encoding/xml"
        "fmt"
)
 
type User1 struct {
        id      uint32
        name    string
        surname string
}
 
type User2 struct {
        Id      uint32
        Name    string
        Surname string
}
 
func main() {
        user1 := User1{
                1,
                "Pepek",
                "Vyskoč"}
 
        user2 := User2{
                1,
                "Pepek",
                "Vyskoč"}
 
        user1asXML, _ := xml.Marshal(user1)
        fmt.Println(string(user1asXML))
 
        fmt.Println()
 
        user2asXML, _ := xml.Marshal(user2)
        fmt.Println(string(user2asXML))
}

Podívejme se nyní na výsledek běhu tohoto příkladu:

<User1></User1>
 
<User2><Id>1</Id><Name>Pepek</Name><Surname>Vyskoč</Surname></User2>
Poznámka: povšimněte si, že první XML obsahuje pouze prázdný kořenový uzel, což je možná na první pohled podivné, neboť datová struktura evidentně obsahuje trojici prvků. Ovšem jména těchto prvků začínají malými písmeny a proto jsou považována za lokální.

Podobně jako při exportu do JSONu lze i při exportu do formátu XML specifikovat jména uzlů (v JSONu jména atributů, tedy klíče). Slouží k tomu speciálně naformátované řetězce přidané k jednotlivým prvkům a začínající prefixem „xml:“. Celý příklad si tedy nepatrně upravíme následujícím způsobem:

package main
 
import (
        "encoding/xml"
        "fmt"
)
 
type User1 struct {
        id      uint32 `xml:"id"`
        name    string `xml:"user_name"`
        surname string `xml:"surname"`
}
 
type User2 struct {
        Id      uint32 `xml:"id"`
        Name    string `xml:"user_name"`
        Surname string `xml:"surname"`
}
 
func main() {
        user1 := User1{
                1,
                "Pepek",
                "Vyskoč"}
 
        user2 := User2{
                1,
                "Pepek",
                "Vyskoč"}
 
        user1asXML, _ := xml.Marshal(user1)
        fmt.Println(string(user1asXML))
 
        fmt.Println()
 
        user2asXML, _ := xml.Marshal(user2)
        fmt.Println(string(user2asXML))
}

Výsledek běhu takto upraveného příkladu:

<User1></User1>
 
<User2><id>1</id><user_name>Pepek</user_name><surname>Vyskoč</surname></User2>

6. Specifikace jména kořenového uzlu, konfigurace odsazení při formátování XML

Na rozdíl od formátu JSON, v němž neexistuje koncept kořenového uzlu (přenáší se jen hodnota jediného objektu, nikoli i jeho název), je v XML použit právě kořenový uzel. V předchozích příkladech bylo jméno tohoto uzlu odvozeno od jména serializované datové struktury (User1 nebo User2), což ovšem nemusí být ve všech případech vyhovující. Ovšem relativně snadno je možné tento nedostatek napravit, a to následujícím způsobem – použitím nového prvku typu xml.Name se specifikovaným jménem. Upravený a vylepšený demonstrační příklad vypadá následovně:

package main
 
import (
        "encoding/xml"
        "fmt"
)
 
type User1 struct {
        XMLName xml.Name `xml:"user"`
        id      uint32   `xml:"id"`
        name    string   `xml:"user_name"`
        surname string   `xml:"surname"`
}
 
type User2 struct {
        XMLName xml.Name `xml:"user"`
        Id      uint32   `xml:"id"`
        Name    string   `xml:"user_name"`
        Surname string   `xml:"surname"`
}
 
func main() {
        user1 := User1{
                id:      1,
                name:    "Pepek",
                surname: "Vyskoč"}
 
        user2 := User2{
                Id:      1,
                Name:    "Pepek",
                Surname: "Vyskoč"}
 
        user1asXML, _ := xml.Marshal(user1)
        fmt.Println(string(user1asXML))
 
        fmt.Println()
 
        user2asXML, _ := xml.Marshal(user2)
        fmt.Println(string(user2asXML))
}

Tento příklad si samozřejmě spustíme. Z výsledku je patrné, že se skutečně změnilo i jméno kořenového uzlu:

<user></user>
 
<user><id>1</id><user_name>Pepek</user_name><surname>Vyskoč</surname></user>

V některých případech je požadováno, aby výsledné XML bylo korektně naformátováno, což se hodí zejména při práci s relativně krátkými konfiguračními soubory atd. Naformátování výsledného XML zajišťuje metoda nazvaná MarshalIndent, které se navíc předá prefix všech řádků (může se jednat o prázdný řetězec) a libovolná sekvence znaků použitá při odsazování vnořených uzlů. Zde můžeme použít například čtyři mezery, znak Tab atd.:

package main
 
import (
        "encoding/xml"
        "fmt"
)
 
type User1 struct {
        XMLName xml.Name `xml:"user"`
        id      uint32   `xml:"id"`
        name    string   `xml:"user_name"`
        surname string   `xml:"surname"`
}
 
type User2 struct {
        XMLName xml.Name `xml:"user"`
        Id      uint32   `xml:"id"`
        Name    string   `xml:"user_name"`
        Surname string   `xml:"surname"`
}
 
func main() {
        user1 := User1{
                id:      1,
                name:    "Pepek",
                surname: "Vyskoč"}
 
        user2 := User2{
                Id:      1,
                Name:    "Pepek",
                Surname: "Vyskoč"}
 
        user1asXML, _ := xml.MarshalIndent(user1, "", "    ")
        fmt.Println(string(user1asXML))
 
        fmt.Println()
 
        user2asXML, _ := xml.MarshalIndent(user2, "", "    ")
        fmt.Println(string(user2asXML))
 
        fmt.Println()
 
        user2asXML, _ = xml.MarshalIndent(user2, "", "\t")
        fmt.Println(string(user2asXML))
 
        fmt.Println()
 
        user2asXML, _ = xml.MarshalIndent(user2, "\t", "\t")
        fmt.Println(string(user2asXML))
}

Zde nás bude zajímat vygenerovaný výsledek, který má tvar:

<user></user>
 
<user>
    <id>1</id>
    <user_name>Pepek</user_name>
    <surname>Vyskoč</surname>
</user>
 
<user>
        <id>1</id>
        <user_name>Pepek</user_name>
        <surname>Vyskoč</surname>
</user>
 
        <user>
                <id>1</id>
                <user_name>Pepek</user_name>
                <surname>Vyskoč</surname>
        </user>
Poznámka: povšimněte si vlivu prefixu v posledním případě. Tento trik lze použít při ručním spojování více XML pod jeden kořenový uzel.

7. Struktura XML odlišná od struktury původních serializovaných dat

Při serializaci datových struktur do formátu XML je možné zvolit odlišnou strukturu výsledného souboru. Pokud například namísto následující struktury:

<user>
    <id>1</id>
    <user_name>Pepek</user_name>
    <surname>Vyskoč</surname>
</user>

Budeme požadovat, aby výsledný soubor XML vypadal odlišně – jméno a příjmení má být ve zvláštním poduzlu:

<user>
    <id>1</id>
    <name>
        <first>Pepek</first>
        <last>Vyskoč</last>
    </name>
</user>

Tohoto chování lze docílit odlišnou specifikací dekorátoru, který je zapsaný za každou datovou položkou, která má být serializována:

type User2 struct {
        XMLName xml.Name `xml:"user"`
        Id      uint32   `xml:"id"`
        Name    string   `xml:"name>first"`
        Surname string   `xml:"name>last"`
}
Poznámka: povšimněte si způsobu zápisu – určujeme nový uzel „name“, v němž se mají vytvořit poduzly „first“ a „last“.

Upravený zdrojový kód tohoto demonstračního příkladu vypadá takto:

package main
 
import (
        "encoding/xml"
        "fmt"
)
 
type User1 struct {
        XMLName xml.Name `xml:"user"`
        id      uint32   `xml:"id"`
        name    string   `xml:"name>first"`
        surname string   `xml:"name>last"`
}
 
type User2 struct {
        XMLName xml.Name `xml:"user"`
        Id      uint32   `xml:"id"`
        Name    string   `xml:"name>first"`
        Surname string   `xml:"name>last"`
}
 
func main() {
        user1 := User1{
                id:      1,
                name:    "Pepek",
                surname: "Vyskoč"}
 
        user2 := User2{
                Id:      1,
                Name:    "Pepek",
                Surname: "Vyskoč"}
 
        user1asXML, _ := xml.MarshalIndent(user1, "", "    ")
        fmt.Println(string(user1asXML))
 
        fmt.Println()
 
        user2asXML, _ := xml.MarshalIndent(user2, "", "    ")
        fmt.Println(string(user2asXML))
 
        fmt.Println()
 
        user2asXML, _ = xml.MarshalIndent(user2, "", "\t")
        fmt.Println(string(user2asXML))
 
        fmt.Println()
 
        user2asXML, _ = xml.MarshalIndent(user2, "\t", "\t")
        fmt.Println(string(user2asXML))
}

Výsledek běhu příkladu (všechny varianty formátování):

<user></user>
 
<user>
    <id>1</id>
    <name>
        <first>Pepek</first>
        <last>Vyskoč</last>
    </name>
</user>
 
<user>
        <id>1</id>
        <name>
                <first>Pepek</first>
                <last>Vyskoč</last>
        </name>
</user>
 
        <user>
                <id>1</id>
                <name>
                        <first>Pepek</first>
                        <last>Vyskoč</last>
                </name>
        </user>

Pochopitelně je možné určit, které hodnoty mají být uloženy ve formě pojmenovaných atributů. Podívejme se na následující demonstrační příklad:

package main
 
import (
        "encoding/xml"
        "fmt"
)
 
type User1 struct {
        XMLName xml.Name `xml:"user"`
        id      uint32   `xml:"id,attr"`
        name    string   `xml:"name&first,attr"`
        surname string   `xml:"name&last,attr"`
}
 
type User2 struct {
        XMLName xml.Name `xml:"user"`
        Id      uint32   `xml:"id,attr"`
        Name    string   `xml:"name&first"`
        Surname string   `xml:"name&last"`
}
 
func main() {
        user1 := User1{
                id:      1,
                name:    "Pepek",
                surname: "Vyskoč"}
 
        user2 := User2{
                Id:      1,
                Name:    "Pepek",
                Surname: "Vyskoč"}

        user1asXML, _ := xml.MarshalIndent(user1, "", "    ")
        fmt.Println(string(user1asXML))
 
        fmt.Println()
 
        user2asXML, _ := xml.MarshalIndent(user2, "", "    ")
        fmt.Println(string(user2asXML))
 
        fmt.Println()
 
        user2asXML, _ = xml.MarshalIndent(user2, "", "\t")
        fmt.Println(string(user2asXML))
 
        fmt.Println()
 
        user2asXML, _ = xml.MarshalIndent(user2, "\t", "\t")
        fmt.Println(string(user2asXML))
}

Výsledek:

<user></user>
 
<user id="1">
    <name>
        <first>Pepek</first>
        <last>Vyskoč</last>
    </name>
</user>
 
<user id="1">
        <name>
                <first>Pepek</first>
                <last>Vyskoč</last>
        </name>
</user>
 
        <user id="1">
                <name>
                        <first>Pepek</first>
                        <last>Vyskoč</last>
                </name>
        </user>

8. Serializace polí, speciální hodnoty, ukazatele apod.

Pro úplnost se ještě podívejme na způsob serializace polí. Následující demonstrační příklad vypadá podobně, jako již výše uvedený příklad na serializaci do formátu JSON, pouze se provede uložení do souboru ve formátu XML:

package main
 
import (
        "encoding/xml"
        "fmt"
)
 
func main() {
        var a1 [10]byte
        var a2 [10]int32
        a3 := [10]int32{1, 10, 2, 9, 3, 8, 4, 7, 5, 6}
        a4 := []string{"www", "root", "cz"}
        a5 := []interface{}{1, "root", 3.1415, true, []int{1, 2, 3, 4}}
        matice := [4][3]float32{
                {1, 2, 3},
                {4, 5, 6},
                {7, 8, 9},
                {0, -1, 0},
        }
 
        a1asXML, _ := xml.Marshal(a1)
        fmt.Println(string(a1asXML))
 
        a2asXML, _ := xml.Marshal(a2)
        fmt.Println(string(a2asXML))
 
        a3asXML, _ := xml.Marshal(a3)
        fmt.Println(string(a3asXML))
 
        a4asXML, _ := xml.Marshal(a4)
        fmt.Println(string(a4asXML))
 
        a5asXML, _ := xml.Marshal(a5)
        fmt.Println(string(a5asXML))
 
        maticeasXML, _ := xml.Marshal(matice)
        fmt.Println(string(maticeasXML))
}

U polí jsme nijak nespecifikovali jména prvků, takže výsledné XML použije jména použitých datových typů (což je většinou v praxi zcela nepoužitelné):

<int32>0</int32><int32>0</int32><int32>0</int32><int32>0</int32><int32>0</int32><int32>0</int32><int32>0</int32><int32>0</int32><int32>0</int32><int32>0</int32>
<int32>1</int32><int32>10</int32><int32>2</int32><int32>9</int32><int32>3</int32><int32>8</int32><int32>4</int32><int32>7</int32><int32>5</int32><int32>6</int32>
<string>www</string><string>root</string><string>cz</string>
<int>1</int><string>root</string><float64>3.1415</float64><bool>true</bool><int>1</int><int>2</int><int>3</int><int>4</int>
<float32>1</float32><float32>2</float32><float32>3</float32><float32>4</float32><float32>5</float32><float32>6</float32><float32>7</float32><float32>8</float32><float32>9</float32><float32>0</float32><float32>-1</float32><float32>0</float32>

Dále se pokusme zjistit, zda a jak vůbec je možné do XML serializovat speciální numerické hodnoty, s nimiž jsme se již seznámili v souvislosti s formátem JSON, tedy nekonečna a NaN. Kromě toho nás bude zajímat práce s ukazateli, protože právě přes ukazatele lze tvořit složitější datové struktury. Příklad nepatrně upravíme takovým způsobem, aby obsahoval lineárně vázaný seznam prvků typu Foobar:

package main
 
import (
        "encoding/xml"
        "fmt"
        "math"
)
 
type Foobar struct {
        XMLName xml.Name `xml:"foobar"`
        Id      uint32   `xml:"id"`
        X       float64  `xml:"x"`
        Y       float64  `xml:"y"`
        Z       float64  `xml:"z"`
        Next    *Foobar  `xml:"foobar"`
}
 
func main() {
        f := Foobar{
                Id:   42,
                X:    math.NaN(),
                Y:    math.Inf(1),
                Z:    math.Inf(-1),
                Next: nil}
 
        g := Foobar{
                Id:   43,
                X:    math.NaN(),
                Y:    math.Inf(1),
                Z:    math.Inf(-1),
                Next: &f}
 
        asXML, err := xml.MarshalIndent(g, "", "    ")
        if err != nil {
                fmt.Println(err)
        } else {
                fmt.Println(string(asXML))
        }
}

Z výstupu – serializované struktury g – je patrné, že z lineárně vázaného seznamu vznikla dvojice vnořených uzlů, což je ostatně jeden z nejlepších způsobů vizualizace této datové struktury. Dále můžeme vidět, že speciální numerické hodnoty jsou skutečně podporovány (záleží jen na kódu pro deserializaci, jak je zpracuje):

<foobar>
    <id>43</id>
    <x>NaN</x>
    <y>+Inf</y>
    <z>-Inf</z>
    <foobar>
        <id>42</id>
        <x>NaN</x>
        <y>+Inf</y>
        <z>-Inf</z>
    </foobar>
</foobar>

9. Serializace sekvence struktur

Velmi často se setkáme s požadavkem na serializaci sekvence nějaké datové struktury. Představme si například seznam uživatelů. Přímé uložení pole je problematické, protože výsledek není validním XML:

package main
 
import (
        "encoding/xml"
        "fmt"
)
 
type User struct {
        XMLName xml.Name `xml:"user"`
        Id      uint32   `xml:"id"`
        Name    string   `xml:"user_name"`
        Surname string   `xml:"surname"`
}
 
func main() {
        var users = [3]User{
                User{
                        Id:      1,
                        Name:    "Pepek",
                        Surname: "Vyskoč"},
                User{
                        Id:      2,
                        Name:    "Pepek",
                        Surname: "Vyskoč"},
                User{
                        Id:      3,
                        Name:    "Josef",
                        Surname: "Vyskočil"},
        }
 
        usersAsXML, _ := xml.MarshalIndent(users, "", "    ")
        fmt.Println(string(usersAsXML))
}

S výsledkem:

<user>
    <id>1</id>
    <user_name>Pepek</user_name>
    <surname>Vyskoč</surname>
</user>
<user>
    <id>2</id>
    <user_name>Pepek</user_name>
    <surname>Vyskoč</surname>
</user>
<user>
    <id>3</id>
    <user_name>Josef</user_name>
    <surname>Vyskočil</surname>
</user>

10. Obalení sekvence struktur dalším datovým typem

V takovém případě bývá nejjednodušší obalit celou strukturu jinou strukturou, která bude obsahovat pouze specifikaci kořenového uzlu a vlastní sekvenci. Zde je navíc kořenový uzel pojmenován:

type Users struct {
        XMLName xml.Name `xml:"users"`
        List    []User
}

Úplný kód příkladu, v němž serializujeme několik uživatelů do formátu XML, vypadá následovně:

package main
 
import (
        "encoding/xml"
        "fmt"
)
 
type User struct {
        Id      uint32 `xml:"id"`
        Name    string `xml:"user_name"`
        Surname string `xml:"surname"`
}
 
type Users struct {
        XMLName xml.Name `xml:"users"`
        List    []User
}
 
func main() {
        var users Users = Users{
                List: []User{
                        User{
                                Id:      1,
                                Name:    "Pepek",
                                Surname: "Vyskoč"},
                        User{
                                Id:      2,
                                Name:    "Pepek",
                                Surname: "Vyskoč"},
                        User{
                                Id:      3,
                                Name:    "Josef",
                                Surname: "Vyskočil"},
                },
        }
 
        usersAsXML, _ := xml.MarshalIndent(users, "", "    ")
        fmt.Println(string(usersAsXML))
}

Výsledek je již mnohem lepší:

<users>
    <List>
        <id>1</id>
        <user_name>Pepek</user_name>
        <surname>Vyskoč</surname>
    </List>
    <List>
        <id>2</id>
        <user_name>Pepek</user_name>
        <surname>Vyskoč</surname>
    </List>
    <List>
        <id>3</id>
        <user_name>Josef</user_name>
        <surname>Vyskočil</surname>
    </List>
</users>

11. Vylepšení předchozích příkladů

Specifikaci jména opakujícího se uzlu (User) lze pochopitelně k této datové struktuře přidat:

type User struct {
        XMLName xml.Name `xml:"user"`
        Id      uint32   `xml:"id"`
        Name    string   `xml:"user_name"`
        Surname string   `xml:"surname"`
}

Potom se kořenový uzel nezmění:

type Users struct {
        XMLName xml.Name `xml:"users"`
        List    []User
}

Můžeme ovšem postupovat i opačně a ponechat původní strukturu User bez uvedení jména uzlu:

type User struct {
        Id      uint32 `xml:"id"`
        Name    string `xml:"user_name"`
        Surname string `xml:"surname"`
}

V tomto případě je vhodnější jméno poduzlů specifikovat v datové struktuře představující kořenový uzel:

type Users struct {
        XMLName xml.Name `xml:"users"`
        List    []User   `xml:"user"`
}

Jen pro úplnost si obě varianty ukažme na úplném zdrojovém kódu.

První varianta:

package main
 
import (
        "encoding/xml"
        "fmt"
)
 
type User struct {
        XMLName xml.Name `xml:"user"`
        Id      uint32   `xml:"id"`
        Name    string   `xml:"user_name"`
        Surname string   `xml:"surname"`
}
 
type Users struct {
        XMLName xml.Name `xml:"users"`
        List    []User
}
 
func main() {
        var users Users = Users{
                List: []User{
                        User{
                                Id:      1,
                                Name:    "Pepek",
                                Surname: "Vyskoč"},
                        User{
                                Id:      2,
                                Name:    "Pepek",
                                Surname: "Vyskoč"},
                        User{
                                Id:      3,
                                Name:    "Josef",
                                Surname: "Vyskočil"},
                },
        }
 
        usersAsXML, _ := xml.MarshalIndent(users, "", "    ")
        fmt.Println(string(usersAsXML))
}

Druhá varianta:

package main
 
import (
        "encoding/xml"
        "fmt"
)
 
type User struct {
        Id      uint32 `xml:"id"`
        Name    string `xml:"user_name"`
        Surname string `xml:"surname"`
}
 
type Users struct {
        XMLName xml.Name `xml:"users"`
        List    []User   `xml:"user"`
}
 
func main() {
        var users Users = Users{
                List: []User{
                        User{
                                Id:      1,
                                Name:    "Pepek",
                                Surname: "Vyskoč"},
                        User{
                                Id:      2,
                                Name:    "Pepek",
                                Surname: "Vyskoč"},
                        User{
                                Id:      3,
                                Name:    "Josef",
                                Surname: "Vyskočil"},
                },
        }
 
        usersAsXML, _ := xml.MarshalIndent(users, "", "    ")
        fmt.Println(string(usersAsXML))
}

12. Serializace jedné struktury jak do JSONu, tak i do XML – problematika anotačních řetězců

Z předchozího textu již víme, jak lze specifikovat formát uložení nějaké datové struktury do formátu JSON i do formátu XML. Ovšem v některých případech je vyžadováno, aby se stejná struktura serializovala i deserializovala do obou těchto formátů. I takového chování je pochopitelně možné docílit, a to navíc poměrně jednoduše – pouze se v anotačním řetězci specifikuje název uzlu v XML a současně i jméno atributu ve formátu JSON:

type User struct {
        XMLName xml.Name `xml:"user" json:"-"`
        Id      uint32   `xml:"id" json:"user_id"`
        Name    string   `xml:"name>first" json:"user_name"`
        Surname string   `xml:"name>last" json:"surname"`
}

Úplný zdrojový kód takto upraveného demonstračního příkladu může vypadat následovně:

package main
 
import (
        "encoding/json"
        "encoding/xml"
        "fmt"
)
 
type User struct {
        XMLName xml.Name `xml:"user" json:"-"`
        Id      uint32   `xml:"id" json:"user_id"`
        Name    string   `xml:"name>first" json:"user_name"`
        Surname string   `xml:"name>last" json:"surname"`
}
 
func main() {
        user := User{
                Id:      1,
                Name:    "Pepek",
                Surname: "Vyskoč"}
 
        userAsXML, _ := xml.MarshalIndent(user, "", "    ")
        fmt.Println(string(userAsXML))
 
        fmt.Println()
 
        userAsJSON, _ := json.Marshal(user)
        fmt.Println(string(userAsJSON))
}

Výsledky jsou očekávané:

<user>
    <id>1</id>
    <name>
        <first>Pepek</first>
        <last>Vyskoč</last>
    </name>
</user>
 
{"user_id":1,"user_name":"Pepek","surname":"Vyskoč"}

13. Binární formáty a programovací jazyk Go

I přesto, že se s výše uvedenými formáty JSON a XML setkáme prakticky ve všech oblastech moderního IT, nemusí se vždy jednat o nejlepší možné řešení problému přenosu strukturovaných dat. Tyto formáty totiž data neukládají v kompaktní binární podobě a navíc je parsing numerických hodnot relativně zdlouhavý, což se projevuje zejména tehdy, pokud je nutné zpracovat skutečně obrovské množství dat (buď mnoho malých zpráv či událostí, nebo naopak rozsáhlé datové soubory). A právě v těchto situacích může být výhodnější sáhnout po nějakém vhodném binárním formátu. Těch již dnes existuje velké množství, od staršího a dosti těžkopádného ASN.1 (Abstract Syntax Notation One) po formáty, které se snaží napodobit některé vlastnosti JSONu. Příkladem může být formát CBOR, jenž je podporován knihovnou https://github.com/fxamacker/cbor, popř. formát BSON, pro který pochopitelně taktéž existuje varianta pro Go. A konečně, ve světě Go se setkáme i s formátem nazvaným gob (Go Objects).

Poznámka: dnes se seznámíme pouze se základním použitím výše zmíněných binárních formátů, podrobnější popis i mnoho dalších demonstračních příkladů bude uvedeno až příště.

14. Formát gob

Prvním binárním formátem, s nímž se setkáme, je formát nazvaný gob neboli Go Objects. Jedná se o formát určený primárně pro použití v programovacím jazyku Go, což znamená, že jeho využití je relativně specifické (ukládání rozsáhlých dat, komunikace mezi dvojicí služeb naprogramovaných v Go atd.). Tento formát umožňuje serializaci prakticky jakékoli datové struktury, ovšem je ho možné použít i pro primitivní datové typy, resp. pro jejich hodnoty. To si ostatně ukážeme v dalším příkladu, v němž jsou serializovaná data zobrazena ve formě sekvence hexadecimálních hodnot:

package main
 
import (
        "bytes"
        "encoding/gob"
        "encoding/hex"
        "fmt"
)
 
func main() {
        var a bool = true
 
        var buffer bytes.Buffer
        encoder := gob.NewEncoder(&buffer)
 
        err := encoder.Encode(a)
        if err != nil {
                fmt.Println(err)
        } else {
                content := buffer.Bytes()
                fmt.Printf("Encoded into %d bytes\n", len(content))
                encoded := hex.EncodeToString(content)
                fmt.Println(encoded)
        }
}

Výsledkem je:

Encoded into 4 bytes
03020001

Formát je v tomto případě jednoduchý:

  1. Délka dat (bez prvního bajtu)
  2. Typ dat
  3. Pozice prvku ve fiktivní struktuře (zde 0=první prvek)
  4. Hodnota (true se převádí na 1)

15. Serializace datové struktury do formátu gob

Do formátu gob lze uložit prakticky jakoukoli datovou strukturu, což se samozřejmě týká i uživatelsky definovaných struktur. Pokusme se tedy uložit obsah struktury typu User. V tomto případě se neuloží pouze vlastní data, ale i základní formát této struktury, což později usnadní deserializaci:

package main
 
import (
        "bytes"
        "encoding/gob"
        "encoding/hex"
        "fmt"
)
 
type User struct {
        Id      uint32
        Name    string
        Surname string
}
 
func main() {
        user := User{
                1,
                "Pepek",
                "Vyskoč"}
 
        var buffer bytes.Buffer
        encoder := gob.NewEncoder(&buffer)
 
        err := encoder.Encode(user)
        if err != nil {
                fmt.Println(err)
        } else {
                content := buffer.Bytes()
                fmt.Printf("Encoded into %d bytes\n", len(content))
                encoded := hex.EncodeToString(content)
                fmt.Println(encoded)
        }
}

Popis struktury User i její obsah se uloží do sekvence 69 bajtů, což je poměrně mnoho, ovšem na rozdíl od JSONu jsou přeneseny i datové typy apod.:

Encoded into 69 bytes
2eff81030101045573657201ff820001030102496401060001044e616d65010c0001075375726e616d65010c00000015ff8201010105506570656b01075679736b6fc48d00

16. Formát CBOR (Concise Binary Object Representation)

Jedním z binárních formátů určených pro přenos prakticky libovolně strukturovaných dat je formát nazvaný CBOR neboli plným jménem Concise Binary Object Representation. Tímto formátem, jenž se snaží nabízet podobné vlastnosti jako JSON (až na možnost jeho přímého čtení člověkem), se budeme podrobněji zabývat v navazující části tohoto seriálu, takže si prozatím jen ukažme jeden příklad, jenž používá knihovnu dostupnou na adrese github.com/fxamacker/cbor/v2 (tu lze nainstalovat běžným způsobem, ovšem pozor – vyžaduje Go 1.13 či novější). V příkladu je ukázána serializace jediné hodnoty, konkrétně pravdivostní hodnoty nastavené na hodnotu true:

package main
 
import (
        "fmt"
        "github.com/fxamacker/cbor/v2"
)
 
func main() {
        var a bool = true
 
        var jsonOutput []byte
 
        cborOutput, _ = cbor.Marshal(a)
        fmt.Println(string(cborOutput))
}
Poznámka: zajímavé je, že tento formát podporuje i numerické hodnoty typu half float, s nimiž jsme se setkali v článku o typu bfloat16.

17. Serializace dat do formátu BSON

Dalším sice relativně novým, ale rozšiřujícím se binárním formátem je formát nazvaný BSON (zde je odkaz na JSON nesporný). Tento formát je podporován v knihovně dodávané společně s ovladači pro MongoDB, ale lze ho používat zcela samostatně a nezávisle. Rozhraní balíčku bson je totožné s rozhraním encoding/json, takže například serializace naší struktury User do souboru typu BSON může vypadat následovně:

Root Linux tip

package main
 
import (
        "fmt"
        "gopkg.in/mgo.v2/bson"
        "io/ioutil"
)
 
type User struct {
        Id      uint32
        Name    string
        Surname string
}
 
func main() {
        user := User{
                1,
                "Pepek",
                "Vyskoč"}
 
        var bsonOutput []byte
 
        bsonOutput, err := bson.Marshal(user)
        if err != nil {
                fmt.Println(err)
        } else {
                fmt.Printf("Encoded into %d bytes\n", len(bsonOutput))
                err := ioutil.WriteFile("1.bson", bsonOutput, 0644)
                if err != nil {
                        fmt.Println(err)
                } else {
                        fmt.Println("And stored into file")
                }
        }
}

18. Deserializace dat z formátu BSON

V předchozím příkladu jsme si ukázali serializaci datové struktury do BSONu, takže nám logicky zbývá provést její zpětnou deserializaci. Postup je velmi jednoduchý a je ukázán v dnešním posledním příkladu. Prozatím si ukazujeme pouze „happy path“, tj. situaci, kdy je deserializace úspěšná, ale příště se budeme zabývat i složitějšími stavy, které mohou v praxi nastat:

package main
 
import (
        "fmt"
        "gopkg.in/mgo.v2/bson"
        "io/ioutil"
)
 
type User struct {
        Id      uint32
        Name    string
        Surname string
}
 
func main() {
        var user User
 
        bsonInput, err := ioutil.ReadFile("1.bson")
        if err != nil {
                fmt.Println(err)
                return
        }
 
        fmt.Printf("Read %d bytes\n", len(bsonInput))
 
        err = bson.Unmarshal(bsonInput, &user)
        if err != nil {
                fmt.Println(err)
                return
        }
        fmt.Println("Deserialized value")
        fmt.Println(user)
}

19. Repositář s demonstračními příklady

Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do Git repositáře, který je dostupný na adrese https://github.com/tisnik/go-root (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má přibližně šest až sedm megabajtů), můžete namísto toho použít odkazy na jednotlivé demonstrační příklady, které naleznete v následující tabulce:

# Příklad Stručný popis Cesta
1 01_json_marshal_floats.go serializace numerických hodnot do formátu JSON https://github.com/tisnik/go-root/blob/master/article57/01_json_mar­shal_floats.go
2 02_json_marshal_floats_specvalues.go serializace speciálních numerických hodnot do formátu JSON https://github.com/tisnik/go-root/blob/master/article57/02_json_mar­shal_floats_specvalues.go
3 03_json_marshal_arrays.go serializace polí (numerických hodnot) do formátu JSON https://github.com/tisnik/go-root/blob/master/article57/03_json_mar­shal_arrays.go
4 04_xml_marshal_struct1.go serializace jednoduchých struktur do XML https://github.com/tisnik/go-root/blob/master/article57/04_xml_mar­shal_struct1.go
5 05_xml_marshal_struct2.go specifikace názvů uzlů při serializaci do XML https://github.com/tisnik/go-root/blob/master/article57/05_xml_mar­shal_struct2.go
6 06_xml_marshal_struct3.go specifikace jména kořenového uzlu https://github.com/tisnik/go-root/blob/master/article57/06_xml_mar­shal_struct3.go
7 07_xml_marshal_struct4_indent.go https://github.com/tisnik/go-root/blob/master/article57/07_xml_mar­shal_struct4_indent.go
8 08_xml_marshal_struct5_control.go řízení, jak má vypadat výsledné XML https://github.com/tisnik/go-root/blob/master/article57/08_xml_mar­shal_struct5_control.go
9 09_xml_marshal_arrays.go serializace polí https://github.com/tisnik/go-root/blob/master/article57/09_xml_mar­shal_arrays.go
10 10_xml_marshal_special_types.go serializace speciálních hodnot, použití ukazatelů https://github.com/tisnik/go-root/blob/master/article57/10_xml_mar­shal_special_types.go
11 11_xml_marshal_array_of_struct1.go serializace sekvence struktur https://github.com/tisnik/go-root/blob/master/article57/11_xml_mar­shal_array_of_struct1.go
12 12_xml_marshal_array_of_struct2.go konfigurace kořenového uzlu https://github.com/tisnik/go-root/blob/master/article57/12_xml_mar­shal_array_of_struct2.go
13 13_xml_marshal_array_of_struct3.go kořenový uzel reprezentovaný vlastní strukturou https://github.com/tisnik/go-root/blob/master/article57/13_xml_mar­shal_array_of_struct3.go
14 14_xml_marshal_array_of_struct4.go kořenový uzel reprezentovaný vlastní strukturou https://github.com/tisnik/go-root/blob/master/article57/14_xml_mar­shal_array_of_struct4.go
15 15_xml_and_json.go serializace jedné struktury jak do XML, tak i do JSONu https://github.com/tisnik/go-root/blob/master/article57/15_xml_an­d_json.go
16 16_gob_marshal_basic_types.go použití formátu Gob https://github.com/tisnik/go-root/blob/master/article57/16_gob_mar­shal_basic_types.go
17 17_gob_marshal_struct.go použití formátu Gob pro serializaci struktur https://github.com/tisnik/go-root/blob/master/article57/17_gob_mar­shal_struct.go
18 18_cbor_basic_types.go základní použití formátu CBOR https://github.com/tisnik/go-root/blob/master/article57/18_cbor_ba­sic_types.go
19 19_bson_serialize.go serializace dat do formátu BSON https://github.com/tisnik/go-root/blob/master/article57/19_bson_se­rialize.go
20 20_bson_deserialize.go deserializace dat z formátu BSON https://github.com/tisnik/go-root/blob/master/article57/20_bson_de­serialize.go

20. Odkazy na Internetu

  1. Gobs of data
    https://blog.golang.org/gobs-of-data
  2. Formát BSON
    http://bsonspec.org/
  3. Golang Guide: A List of Top Golang Frameworks, IDEs & Tools
    https://blog.intelligentbe­e.com/2017/08/14/golang-guide-list-top-golang-frameworks-ides-tools/
  4. Repositář projektu Gift
    https://github.com/disinte­gration/gift
  5. Dokumentace k projektu Gift
    https://godoc.org/github.com/di­sintegration/gift
  6. Online x86 / x64 Assembler and Disassembler
    https://defuse.ca/online-x86-assembler.htm#disassembly2
  7. The Design of the Go Assembler
    https://talks.golang.org/2016/as­m.slide#1
  8. A Quick Guide to Go's Assembler
    https://golang.org/doc/asm
  9. AssemblyPolicy
    https://github.com/golang/go/wi­ki/AssemblyPolicy
  10. Geohash in Golang Assembly
    https://mmcloughlin.com/posts/geohash-assembly
  11. Command objdump
    https://golang.org/cmd/objdump/
  12. Assembly
    https://goroutines.com/asm
  13. Go & Assembly
    http://www.doxsey.net/blog/go-and-assembly
  14. A Foray Into Go Assembly Programming
    https://blog.sgmansfield.com/2017/04/a-foray-into-go-assembly-programming/
  15. Golang Capturing log.Println And fmt.Println Output
    https://medium.com/@hau12a1/golang-capturing-log-println-and-fmt-println-output-770209c791b4
  16. Stránka projektu plotly
    https://plot.ly/
  17. Plotly JavaScript Open Source Graphing Library
    https://plot.ly/javascript/
  18. Domain coloring
    https://en.wikipedia.org/wi­ki/Domain_coloring
  19. Michael Fogleman's projects
    https://www.michaelfogleman­.com/projects/tagged/grap­hics/
  20. Color Graphs of Complex Functions
    https://web.archive.org/web/20120511021419/htt­p://w.american.edu/cas/mat­hstat/lcrone/ComplexPlot.html
  21. A Gallery of Complex Functions
    http://wismuth.com/complex/ga­llery.html
  22. package glot
    https://godoc.org/github.com/A­rafatk/glot
  23. Gnuplotting: Output terminals
    http://www.gnuplotting.org/output-terminals/
  24. Introducing Glot the plotting library for Golang
    https://medium.com/@Arafat­./introducing-glot-the-plotting-library-for-golang-3133399948a1
  25. Introducing Glot the plotting library for Golang
    https://blog.gopheracademy.com/advent-2018/introducing-glot/
  26. Glot is a plotting library for Golang built on top of gnuplot
    https://github.com/Arafatk/glot
  27. Example plots (gonum/plot)
    https://github.com/gonum/plot/wi­ki/Example-plots
  28. A repository for plotting and visualizing data (gonum/plot)
    https://github.com/gonum/plot
  29. golang library to make https://chartjs.org/ plots
    https://github.com/brentp/go-chartjs
  30. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  31. The Gonum Numerical Computing Package
    https://www.gonum.org/pos­t/introtogonum/
  32. Gomacro na GitHubu
    https://github.com/cosmos72/gomacro
  33. gophernotes – Use Go in Jupyter notebooks and nteract
    https://github.com/gopher­data/gophernotes
  34. gonum
    https://github.com/gonum
  35. go-gota/gota – DataFrames and data wrangling in Go (Golang)
    https://porter.io/github.com/go-gota/gota
  36. A repository for plotting and visualizing data
    https://github.com/gonum/plot
  37. Gonum Numerical Packages
    https://www.gonum.org/
  38. Stránky projektu MinIO
    https://min.io/
  39. MinIO Quickstart Guide
    https://docs.min.io/docs/minio-quickstart-guide.html
  40. MinIO Go Client API Reference
    https://docs.min.io/docs/golang-client-api-reference
  41. MinIO Python Client API Reference
    https://docs.min.io/docs/python-client-api-reference.html
  42. Performance at Scale: MinIO Pushes Past 1.4 terabits per second with 256 NVMe Drives
    https://blog.min.io/performance-at-scale-minio-pushes-past-1–3-terabits-per-second-with-256-nvme-drives/
  43. Benchmarking MinIO vs. AWS S3 for Apache Spark
    https://blog.min.io/benchmarking-apache-spark-vs-aws-s3/
  44. MinIO Client Quickstart Guide
    https://docs.min.io/docs/minio-client-quickstart-guide.html
  45. Analýza kvality zdrojových kódů Minia
    https://goreportcard.com/re­port/github.com/minio/minio
  46. This is MinIO
    https://www.youtube.com/wat­ch?v=vF0lQh0XOCs
  47. Running MinIO Standalone
    https://www.youtube.com/wat­ch?v=dIQsPCHvHoM
  48. „Amazon S3 Compatible Storage in Kubernetes“ – Rob Girard, Principal Tech Marketing Engineer, Minio
    https://www.youtube.com/wat­ch?v=wlpn8K0jJ4U
  49. Ginkgo
    http://onsi.github.io/ginkgo/
  50. Gomega
    https://onsi.github.io/gomega/
  51. Ginkgo's Preferred Matcher Library na GitHubu
    https://github.com/onsi/gomega/
  52. Provided Matchers
    http://onsi.github.io/gomega/#provided-matchers
  53. Dokumentace k balíčku goexpect
    https://godoc.org/github.com/go­ogle/goexpect
  54. Balíček goexpect
    https://github.com/google/goexpect
  55. Balíček go-expect
    https://github.com/Netflix/go-expect
  56. Balíček gexpect
    https://github.com/Thomas­Rooney/gexpect
  57. Expect (originál naprogramovaný v TCL)
    https://core.tcl-lang.org/expect/index
  58. Expect (Wikipedia)
    https://en.wikipedia.org/wiki/Expect
  59. Pexpect
    https://pexpect.readthedoc­s.io/en/stable/
  60. Golang SSH Client: Multiple Commands, Crypto & Goexpect Examples
    http://networkbit.ch/golang-ssh-client/
  61. goblin na GitHubu
    https://github.com/franela/goblin
  62. Mocha framework
    https://mochajs.org/
  63. frisby na GitHubu
    https://github.com/verdverm/frisby
  64. package frisby
    https://godoc.org/github.com/ver­dverm/frisby
  65. Frisby alternatives and similar packages (generováno)
    https://go.libhunt.com/frisby-alternatives
  66. Cucumber for golang
    https://github.com/DATA-DOG/godog
  67. How to Use Godog for Behavior-driven Development in Go
    https://semaphoreci.com/com­munity/tutorials/how-to-use-godog-for-behavior-driven-development-in-go
  68. Comparative Analysis Of GoLang Testing Frameworks
    https://www.slideshare.net/Dushy­antBhalgami/comparative-analysis-of-golang-testing-frameworks
  69. A Quick Guide to Testing in Golang
    https://caitiem.com/2016/08/18/a-quick-guide-to-testing-in-golang/
  70. Tom's Obvious, Minimal Language.
    https://github.com/toml-lang/toml
  71. xml.org
    http://www.xml.org/
  72. Soubory .properties
    https://en.wikipedia.org/wi­ki/.properties
  73. Soubory INI
    https://en.wikipedia.org/wi­ki/INI_file
  74. JSON to YAML
    https://www.json2yaml.com/
  75. Data Format Converter
    https://toolkit.site/format.html
  76. Viper na GitHubu
    https://github.com/spf13/viper
  77. GoDotEnv na GitHubu
    https://github.com/joho/godotenv
  78. The fantastic ORM library for Golang
    http://gorm.io/
  79. Dokumentace k balíčku gorilla/mux
    https://godoc.org/github.com/go­rilla/mux
  80. Gorilla web toolkitk
    http://www.gorillatoolkit.org/
  81. Metric types
    https://prometheus.io/doc­s/concepts/metric_types/
  82. Histograms with Prometheus: A Tale of Woe
    http://linuxczar.net/blog/2017/06/15/pro­metheus-histogram-2/
  83. Why are Prometheus histograms cumulative?
    https://www.robustperception.io/why-are-prometheus-histograms-cumulative
  84. Histograms and summaries
    https://prometheus.io/doc­s/practices/histograms/
  85. Instrumenting Golang server in 5 min
    https://medium.com/@gsisi­mogang/instrumenting-golang-server-in-5-min-c1c32489add3
  86. Semantic Import Versioning in Go
    https://www.aaronzhuo.com/semantic-import-versioning-in-go/
  87. Sémantické verzování
    https://semver.org/
  88. Getting started with Go modules
    https://medium.com/@fonse­ka.live/getting-started-with-go-modules-b3dac652066d
  89. Create projects independent of $GOPATH using Go Modules
    https://medium.com/mindorks/create-projects-independent-of-gopath-using-go-modules-802260cdfb51o
  90. Anatomy of Modules in Go
    https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16
  91. Modules
    https://github.com/golang/go/wi­ki/Modules
  92. Go Modules Tutorial
    https://tutorialedge.net/golang/go-modules-tutorial/
  93. Module support
    https://golang.org/cmd/go/#hdr-Module_support
  94. Go Lang: Memory Management and Garbage Collection
    https://vikash1976.wordpres­s.com/2017/03/26/go-lang-memory-management-and-garbage-collection/
  95. Golang Internals, Part 4: Object Files and Function Metadata
    https://blog.altoros.com/golang-part-4-object-files-and-function-metadata.html
  96. What is REPL?
    https://pythonprogramminglan­guage.com/repl/
  97. What is a REPL?
    https://codewith.mu/en/tu­torials/1.0/repl
  98. Programming at the REPL: Introduction
    https://clojure.org/guides/re­pl/introduction
  99. What is REPL? (Quora)
    https://www.quora.com/What-is-REPL
  100. Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
    https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/
  101. Read-eval-print loop (Wikipedia)
    https://en.wikipedia.org/wi­ki/Read%E2%80%93eval%E2%80%93prin­t_loop
  102. Vim as a Go (Golang) IDE using LSP and vim-go
    https://octetz.com/posts/vim-as-go-ide
  103. gopls
    https://github.com/golang/go/wi­ki/gopls
  104. IDE Integration Guide
    https://github.com/stamble­rre/gocode/blob/master/doc­s/IDE_integration.md
  105. How to instrument Go code with custom expvar metrics
    https://sysdig.com/blog/golang-expvar-custom-metrics/
  106. Golang expvar metricset (Metricbeat Reference)
    https://www.elastic.co/gu­ide/en/beats/metricbeat/7­.x/metricbeat-metricset-golang-expvar.html
  107. Package expvar
    https://golang.org/pkg/expvar/#NewInt
  108. Java Platform Debugger Architecture: Overview
    https://docs.oracle.com/en/ja­va/javase/11/docs/specs/jpda/jpda­.html
  109. The JVM Tool Interface (JVM TI): How VM Agents Work
    https://www.oracle.com/technet­work/articles/javase/index-140680.html
  110. JVM Tool Interface Version 11.0
    https://docs.oracle.com/en/ja­va/javase/11/docs/specs/jvmti­.html
  111. Creating a Debugging and Profiling Agent with JVMTI
    http://www.oracle.com/technet­work/articles/javase/jvmti-136367.html
  112. JVM TI (Wikipedia)
    http://en.wikipedia.org/wiki/JVM_TI
  113. IBM JVMTI extensions
    http://publib.boulder.ibm­.com/infocenter/realtime/v2r0/in­dex.jsp?topic=%2Fcom.ibm.sof­trt.doc%2Fdiag%2Ftools%2Fjvmti_ex­tensions.html
  114. Go & cgo: integrating existing C code with Go
    http://akrennmair.github.io/golang-cgo-slides/#1
  115. Using cgo to call C code from within Go code
    https://wenzr.wordpress.com/2018/06/07/u­sing-cgo-to-call-c-code-from-within-go-code/
  116. Package trace
    https://golang.org/pkg/runtime/trace/
  117. Introducing HTTP Tracing
    https://blog.golang.org/http-tracing
  118. Command trace
    https://golang.org/cmd/trace/
  119. A StreamLike, Immutable, Lazy Loading and smart Golang Library to deal with slices
    https://github.com/wesovilabs/koazee
  120. Funkce vyššího řádu v knihovně Underscore
    https://www.root.cz/clanky/funkce-vyssiho-radu-v-knihovne-underscore/
  121. Delve: a debugger for the Go programming language.
    https://github.com/go-delve/delve
  122. Příkazy debuggeru Delve
    https://github.com/go-delve/delve/tree/master/Do­cumentation/cli
  123. Debuggery a jejich nadstavby v Linuxu
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/
  124. Debuggery a jejich nadstavby v Linuxu (2. část)
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/
  125. Debuggery a jejich nadstavby v Linuxu (3): Nemiver
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/
  126. Debuggery a jejich nadstavby v Linuxu (4): KDbg
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/
  127. Debuggery a jejich nadstavby v Linuxu (5): ladění aplikací v editorech Emacs a Vim
    http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-5-ladeni-aplikaci-v-editorech-emacs-a-vim/
  128. Debugging Go Code with GDB
    https://golang.org/doc/gdb
  129. Debugging Go (golang) programs with gdb
    https://thornydev.blogspot­.com/2014/01/debugging-go-golang-programs-with-gdb.html
  130. GDB – Dokumentace
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/
  131. GDB – Supported Languages
    http://sourceware.org/gdb/cu­rrent/onlinedocs/gdb/Suppor­ted-Languages.html#Supported-Languages
  132. GNU Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/GNU_Debugger
  133. The LLDB Debugger
    http://lldb.llvm.org/
  134. Debugger (Wikipedia)
    https://en.wikipedia.org/wi­ki/Debugger
  135. 13 Linux Debuggers for C++ Reviewed
    http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817
  136. Go is on a Trajectory to Become the Next Enterprise Programming Language
    https://hackernoon.com/go-is-on-a-trajectory-to-become-the-next-enterprise-programming-language-3b75d70544e
  137. Go Proverbs: Simple, Poetic, Pithy
    https://go-proverbs.github.io/
  138. Handling Sparse Files on Linux
    https://www.systutorials.com/136652/han­dling-sparse-files-on-linux/
  139. Gzip (Wikipedia)
    https://en.wikipedia.org/wiki/Gzip
  140. Deflate
    https://en.wikipedia.org/wiki/DEFLATE
  141. 10 tools written in Go that every developer needs to know
    https://gustavohenrique.net/en/2019/01/10-tools-written-in-go-that-every-dev-needs-to-know/
  142. Hexadecimální prohlížeče a editory s textovým uživatelským rozhraním
    https://www.root.cz/clanky/he­xadecimalni-prohlizece-a-editory-s-textovym-uzivatelskym-rozhranim/
  143. Hex dump
    https://en.wikipedia.org/wi­ki/Hex_dump
  144. Rozhraní io.ByteReader
    https://golang.org/pkg/io/#ByteReader
  145. Rozhraní io.RuneReader
    https://golang.org/pkg/io/#RuneReader
  146. Rozhraní io.ByteScanner
    https://golang.org/pkg/io/#By­teScanner
  147. Rozhraní io.RuneScanner
    https://golang.org/pkg/io/#Ru­neScanner
  148. Rozhraní io.Closer
    https://golang.org/pkg/io/#Closer
  149. Rozhraní io.Reader
    https://golang.org/pkg/io/#Reader
  150. Rozhraní io.Writer
    https://golang.org/pkg/io/#Writer
  151. Typ Strings.Reader
    https://golang.org/pkg/strin­gs/#Reader
  152. VACUUM (SQL)
    https://www.sqlite.org/lan­g_vacuum.html
  153. VACUUM (Postgres)
    https://www.postgresql.or­g/docs/8.4/sql-vacuum.html
  154. go-cron
    https://github.com/rk/go-cron
  155. gocron
    https://github.com/jasonlvhit/gocron
  156. clockwork
    https://github.com/whiteShtef/cloc­kwork
  157. clockwerk
    https://github.com/onatm/clockwerk
  158. JobRunner
    https://github.com/bamzi/jobrunner
  159. Rethinking Cron
    https://adam.herokuapp.com/pas­t/2010/4/13/rethinking_cron/
  160. In the Beginning was the Command Line
    https://web.archive.org/web/20180218045352/htt­p://www.cryptonomicon.com/be­ginning.html
  161. repl.it (REPL pro různé jazyky)
    https://repl.it/languages
  162. GOCUI – Go Console User Interface (celé uživatelské prostředí, nejenom input box)
    https://github.com/jroimartin/gocui
  163. Read–eval–print loop
    https://en.wikipedia.org/wi­ki/Read%E2%80%93eval%E2%80%93prin­t_loop
  164. go-prompt
    https://github.com/c-bata/go-prompt
  165. readline
    https://github.com/chzyer/readline
  166. A pure golang implementation for GNU-Readline kind library
    https://golangexample.com/a-pure-golang-implementation-for-gnu-readline-kind-library/
  167. go-readline
    https://github.com/fiorix/go-readline
  168. 4 Python libraries for building great command-line user interfaces
    https://opensource.com/article/17/5/4-practical-python-libraries
  169. prompt_toolkit 2.0.3 na PyPi
    https://pypi.org/project/prom­pt_toolkit/
  170. python-prompt-toolkit na GitHubu
    https://github.com/jonathan­slenders/python-prompt-toolkit
  171. The GNU Readline Library
    https://tiswww.case.edu/php/chet/re­adline/rltop.html
  172. GNU Readline (Wikipedia)
    https://en.wikipedia.org/wi­ki/GNU_Readline
  173. readline — GNU readline interface (Python 3.x)
    https://docs.python.org/3/li­brary/readline.html
  174. readline — GNU readline interface (Python 2.x)
    https://docs.python.org/2/li­brary/readline.html
  175. GNU Readline Library – command line editing
    https://tiswww.cwru.edu/php/chet/re­adline/readline.html
  176. gnureadline 6.3.8 na PyPi
    https://pypi.org/project/gnureadline/
  177. Editline Library (libedit)
    http://thrysoee.dk/editline/
  178. Comparing Python Command-Line Parsing Libraries – Argparse, Docopt, and Click
    https://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/
  179. libedit or editline
    http://www.cs.utah.edu/~bi­gler/code/libedit.html
  180. WinEditLine
    http://mingweditline.sourceforge.net/
  181. rlcompleter — Completion function for GNU readline
    https://docs.python.org/3/li­brary/rlcompleter.html
  182. rlwrap na GitHubu
    https://github.com/hanslub42/rlwrap
  183. rlwrap(1) – Linux man page
    https://linux.die.net/man/1/rlwrap
  184. readline(3) – Linux man page
    https://linux.die.net/man/3/readline
  185. history(3) – Linux man page
    https://linux.die.net/man/3/history
  186. Dokumentace k balíčku oglematchers
    https://godoc.org/github.com/ja­cobsa/oglematchers
  187. Balíček oglematchers
    https://github.com/jacobsa/o­glematchers
  188. Dokumentace k balíčku ogletest
    https://godoc.org/github.com/ja­cobsa/ogletest
  189. Balíček ogletest
    https://github.com/jacobsa/ogletest
  190. Dokumentace k balíčku assert
    https://godoc.org/github.com/stret­chr/testify/assert
  191. Testify – Thou Shalt Write Tests
    https://github.com/stretchr/testify/
  192. package testing
    https://golang.org/pkg/testing/
  193. Golang basics – writing unit tests
    https://blog.alexellis.io/golang-writing-unit-tests/
  194. An Introduction to Programming in Go / Testing
    https://www.golang-book.com/books/intro/12
  195. An Introduction to Testing in Go
    https://tutorialedge.net/golang/intro-testing-in-go/
  196. Advanced Go Testing Tutorial
    https://tutorialedge.net/go­lang/advanced-go-testing-tutorial/
  197. GoConvey
    http://goconvey.co/
  198. Testing Techniques
    https://talks.golang.org/2014/tes­ting.slide
  199. 5 simple tips and tricks for writing unit tests in #golang
    https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742
  200. Afinní transformace
    https://cs.wikibooks.org/wi­ki/Geometrie/Afinn%C3%AD_tran­sformace_sou%C5%99adnic
  201. package gg
    https://godoc.org/github.com/fo­gleman/gg
  202. Generate an animated GIF with Golang
    http://tech.nitoyon.com/en/blog/2016/01/07/­go-animated-gif-gen/
  203. Generate an image programmatically with Golang
    http://tech.nitoyon.com/en/blog/2015/12/31/­go-image-gen/
  204. The Go image package
    https://blog.golang.org/go-image-package
  205. Balíček draw2D: 2D rendering for different output (raster, pdf, svg)
    https://github.com/llgcode/draw2d
  206. Draw a rectangle in Golang?
    https://stackoverflow.com/qu­estions/28992396/draw-a-rectangle-in-golang
  207. YAML
    https://yaml.org/
  208. edn
    https://github.com/edn-format/edn
  209. Smile
    https://github.com/FasterXML/smile-format-specification
  210. Protocol-Buffers
    https://developers.google.com/protocol-buffers/
  211. Marshalling (computer science)
    https://en.wikipedia.org/wi­ki/Marshalling_(computer_sci­ence)
  212. Unmarshalling
    https://en.wikipedia.org/wi­ki/Unmarshalling
  213. Introducing JSON
    http://json.org/
  214. Package json
    https://golang.org/pkg/encoding/json/
  215. The Go Blog: JSON and Go
    https://blog.golang.org/json-and-go
  216. Go by Example: JSON
    https://gobyexample.com/json
  217. Writing Web Applications
    https://golang.org/doc/articles/wiki/
  218. Golang Web Apps
    https://www.reinbach.com/blog/golang-webapps-1/
  219. Build web application with Golang
    https://legacy.gitbook.com/bo­ok/astaxie/build-web-application-with-golang/details
  220. Golang Templates – Golang Web Pages
    https://www.youtube.com/wat­ch?v=TkNIETmF-RU
  221. Simple Golang HTTPS/TLS Examples
    https://github.com/denji/golang-tls
  222. Playing with images in HTTP response in golang
    https://www.sanarias.com/blog/1214Pla­yingwithimagesinHTTPrespon­seingolang
  223. MIME Types List
    https://www.freeformatter.com/mime-types-list.html
  224. Go Mutex Tutorial
    https://tutorialedge.net/golang/go-mutex-tutorial/
  225. Creating A Simple Web Server With Golang
    https://tutorialedge.net/go­lang/creating-simple-web-server-with-golang/
  226. Building a Web Server in Go
    https://thenewstack.io/building-a-web-server-in-go/
  227. How big is the pipe buffer?
    https://unix.stackexchange­.com/questions/11946/how-big-is-the-pipe-buffer
  228. How to turn off buffering of stdout in C
    https://stackoverflow.com/qu­estions/7876660/how-to-turn-off-buffering-of-stdout-in-c
  229. setbuf(3) – Linux man page
    https://linux.die.net/man/3/setbuf
  230. setvbuf(3) – Linux man page (stejný obsah jako předchozí stránka)
    https://linux.die.net/man/3/setvbuf
  231. Select waits on a group of channels
    https://yourbasic.org/golang/select-explained/
  232. Rob Pike: Simplicity is Complicated (video)
    http://www.golang.to/posts/dotgo-2015-rob-pike-simplicity-is-complicated-youtube-16893
  233. Algorithms to Go
    https://yourbasic.org/
  234. Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů
    https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu/
  235. Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů: vlastní filtry a lexery
    https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu-vlastni-filtry-a-lexery/
  236. Go Defer Simplified with Practical Visuals
    https://blog.learngoprogram­ming.com/golang-defer-simplified-77d3b2b817ff
  237. 5 More Gotchas of Defer in Go — Part II
    https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa
  238. The Go Blog: Defer, Panic, and Recover
    https://blog.golang.org/defer-panic-and-recover
  239. The defer keyword in Swift 2: try/finally done right
    https://www.hackingwithswift.com/new-syntax-swift-2-defer
  240. Swift Defer Statement
    https://andybargh.com/swift-defer-statement/
  241. Modulo operation (Wikipedia)
    https://en.wikipedia.org/wi­ki/Modulo_operation
  242. Node.js vs Golang: Battle of the Next-Gen Languages
    https://www.hostingadvice­.com/blog/nodejs-vs-golang/
  243. The Go Programming Language (home page)
    https://golang.org/
  244. GoDoc
    https://godoc.org/
  245. Go (programming language), Wikipedia
    https://en.wikipedia.org/wi­ki/Go_(programming_langua­ge)
  246. Go Books (kniha o jazyku Go)
    https://github.com/dariubs/GoBooks
  247. The Go Programming Language Specification
    https://golang.org/ref/spec
  248. Go: the Good, the Bad and the Ugly
    https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/
  249. Package builtin
    https://golang.org/pkg/builtin/
  250. Package fmt
    https://golang.org/pkg/fmt/
  251. The Little Go Book (další kniha)
    https://github.com/dariubs/GoBooks
  252. The Go Programming Language by Brian W. Kernighan, Alan A. A. Donovan
    https://www.safaribookson­line.com/library/view/the-go-programming/9780134190570/e­book_split010.html
  253. Learning Go
    https://www.miek.nl/go/
  254. Go Bootcamp
    http://www.golangbootcamp.com/
  255. Programming in Go: Creating Applications for the 21st Century (další kniha o jazyku Go)
    http://www.informit.com/sto­re/programming-in-go-creating-applications-for-the-21st-9780321774637
  256. Introducing Go (Build Reliable, Scalable Programs)
    http://shop.oreilly.com/pro­duct/0636920046516.do
  257. Learning Go Programming
    https://www.packtpub.com/application-development/learning-go-programming
  258. The Go Blog
    https://blog.golang.org/
  259. Getting to Go: The Journey of Go's Garbage Collector
    https://blog.golang.org/ismmkeynote
  260. Go (programovací jazyk, Wikipedia)
    https://cs.wikipedia.org/wi­ki/Go_(programovac%C3%AD_ja­zyk)
  261. Rychle, rychleji až úplně nejrychleji s jazykem Go
    https://www.root.cz/clanky/rychle-rychleji-az-uplne-nejrychleji-s-jazykem-go/
  262. Installing Go on the Raspberry Pi
    https://dave.cheney.net/2012/09/25/in­stalling-go-on-the-raspberry-pi
  263. How the Go runtime implements maps efficiently (without generics)
    https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-efficiently-without-generics
  264. Niečo málo o Go – Golang (slovensky)
    http://golangsk.logdown.com/
  265. How Many Go Developers Are There?
    https://research.swtch.com/gop­hercount
  266. Most Popular Technologies (Stack Overflow Survery 2018)
    https://insights.stackover­flow.com/survey/2018/#most-popular-technologies
  267. Most Popular Technologies (Stack Overflow Survery 2017)
    https://insights.stackover­flow.com/survey/2017#techno­logy
  268. JavaScript vs. Golang for IoT: Is Gopher Winning?
    https://www.iotforall.com/javascript-vs-golang-iot/
  269. The Go Programming Language: Release History
    https://golang.org/doc/de­vel/release.html
  270. Go 1.11 Release Notes
    https://golang.org/doc/go1.11
  271. Go 1.10 Release Notes
    https://golang.org/doc/go1.10
  272. Go 1.9 Release Notes (tato verze je stále používána)
    https://golang.org/doc/go1.9
  273. Go 1.8 Release Notes (i tato verze je stále používána)
    https://golang.org/doc/go1.8
  274. Go on Fedora
    https://developer.fedorapro­ject.org/tech/languages/go/go-installation.html
  275. Writing Go programs
    https://developer.fedorapro­ject.org/tech/languages/go/go-programs.html
  276. The GOPATH environment variable
    https://tip.golang.org/doc/co­de.html#GOPATH
  277. Command gofmt
    https://tip.golang.org/cmd/gofmt/
  278. The Go Blog: go fmt your code
    https://blog.golang.org/go-fmt-your-code
  279. C? Go? Cgo!
    https://blog.golang.org/c-go-cgo
  280. Spaces vs. Tabs: A 20-Year Debate Reignited by Google’s Golang
    https://thenewstack.io/spaces-vs-tabs-a-20-year-debate-and-now-this-what-the-hell-is-wrong-with-go/
  281. 400,000 GitHub repositories, 1 billion files, 14 terabytes of code: Spaces or Tabs?
    https://medium.com/@hoffa/400–000-github-repositories-1-billion-files-14-terabytes-of-code-spaces-or-tabs-7cfe0b5dd7fd
  282. Gofmt No Longer Allows Spaces. Tabs Only
    https://news.ycombinator.com/i­tem?id=7914523
  283. Why does Go „go fmt“ uses tabs instead of whitespaces?
    https://www.quora.com/Why-does-Go-go-fmt-uses-tabs-instead-of-whitespaces
  284. Interactive: The Top Programming Languages 2018
    https://spectrum.ieee.org/sta­tic/interactive-the-top-programming-languages-2018
  285. Go vs. Python
    https://www.peterbe.com/plog/govspy
  286. PackageManagementTools
    https://github.com/golang/go/wi­ki/PackageManagementTools
  287. A Tour of Go: Type inference
    https://tour.golang.org/basics/14
  288. Go Slices: usage and internals
    https://blog.golang.org/go-slices-usage-and-internals
  289. Go by Example: Slices
    https://gobyexample.com/slices
  290. What is the point of slice type in Go?
    https://stackoverflow.com/qu­estions/2098874/what-is-the-point-of-slice-type-in-go
  291. The curious case of Golang array and slices
    https://medium.com/@hackintoshrao/the-curious-case-of-golang-array-and-slices-2565491d4335
  292. Introduction to Slices in Golang
    https://www.callicoder.com/golang-slices/
  293. Golang: Understanding ‚null‘ and nil
    https://newfivefour.com/golang-null-nil.html
  294. What does nil mean in golang?
    https://stackoverflow.com/qu­estions/35983118/what-does-nil-mean-in-golang
  295. nils In Go
    https://go101.org/article/nil.html
  296. Go slices are not dynamic arrays
    https://appliedgo.net/slices/
  297. Go-is-no-good (nelze brát doslova)
    https://github.com/ksimka/go-is-not-good
  298. Rust vs. Go
    https://news.ycombinator.com/i­tem?id=13430108
  299. Seriál Programovací jazyk Rust
    https://www.root.cz/seria­ly/programovaci-jazyk-rust/
  300. Modern garbage collection: A look at the Go GC strategy
    https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e
  301. Go GC: Prioritizing low latency and simplicity
    https://blog.golang.org/go15gc
  302. Is Golang a good language for embedded systems?
    https://www.quora.com/Is-Golang-a-good-language-for-embedded-systems
  303. Running GoLang on an STM32 MCU. A quick tutorial.
    https://www.mickmake.com/post/running-golang-on-an-mcu-a-quick-tutorial
  304. Go, Robot, Go! Golang Powered Robotics
    https://gobot.io/
  305. Emgo: Bare metal Go (language for programming embedded systems)
    https://github.com/ziutek/emgo
  306. UTF-8 history
    https://www.cl.cam.ac.uk/~mgk25/uc­s/utf-8-history.txt
  307. Less is exponentially more
    https://commandcenter.blog­spot.com/2012/06/less-is-exponentially-more.html
  308. Should I Rust, or Should I Go
    https://codeburst.io/should-i-rust-or-should-i-go-59a298e00ea9
  309. Setting up and using gccgo
    https://golang.org/doc/install/gccgo
  310. Elastic Tabstops
    http://nickgravgaard.com/elastic-tabstops/
  311. Strings, bytes, runes and characters in Go
    https://blog.golang.org/strings
  312. Datový typ
    https://cs.wikipedia.org/wi­ki/Datov%C3%BD_typ
  313. Seriál o programovacím jazyku Rust: Základní (primitivní) datové typy
    https://www.root.cz/clanky/pro­gramovaci-jazyk-rust-nahrada-c-nebo-slepa-cesta/#k09
  314. Seriál o programovacím jazyku Rust: Vytvoření „řezu“ z pole
    https://www.root.cz/clanky/prace-s-poli-v-programovacim-jazyku-rust/#k06
  315. Seriál o programovacím jazyku Rust: Řezy (slice) vektoru
    https://www.root.cz/clanky/prace-s-vektory-v-programovacim-jazyku-rust/#k05
  316. Printf Format Strings
    https://www.cprogramming.com/tu­torial/printf-format-strings.html
  317. Java: String.format
    https://docs.oracle.com/ja­vase/8/docs/api/java/lang/Strin­g.html#format-java.lang.String-java.lang.Object…-
  318. Java: format string syntax
    https://docs.oracle.com/ja­vase/8/docs/api/java/util/For­matter.html#syntax
  319. Selectors
    https://golang.org/ref/spec#Selectors
  320. Calling Go code from Python code
    http://savorywatt.com/2015/09/18/ca­lling-go-code-from-python-code/
  321. Go Data Structures: Interfaces
    https://research.swtch.com/interfaces
  322. How to use interfaces in Go
    http://jordanorelli.com/pos­t/32665860244/how-to-use-interfaces-in-go
  323. Interfaces in Go (part I)
    https://medium.com/golangspec/in­terfaces-in-go-part-i-4ae53a97479c
  324. Part 21: Goroutines
    https://golangbot.com/goroutines/
  325. Part 22: Channels
    https://golangbot.com/channels/
  326. [Go] Lightweight eventbus with async compatibility for Go
    https://github.com/asaske­vich/EventBus
  327. What about Trait support in Golang?
    https://www.reddit.com/r/go­lang/comments/8mfykl/what_a­bout_trait_support_in_golan­g/
  328. Don't Get Bitten by Pointer vs Non-Pointer Method Receivers in Golang
    https://nathanleclaire.com/blog/2014/08/09/dont-get-bitten-by-pointer-vs-non-pointer-method-receivers-in-golang/
  329. Control Flow
    https://en.wikipedia.org/wi­ki/Control_flow
  330. Structured programming
    https://en.wikipedia.org/wi­ki/Structured_programming
  331. Control Structures
    https://www.golang-book.com/books/intro/5
  332. Control structures – Go if else statement
    http://golangtutorials.blog­spot.com/2011/06/control-structures-if-else-statement.html
  333. Control structures – Go switch case statement
    http://golangtutorials.blog­spot.com/2011/06/control-structures-go-switch-case.html
  334. Control structures – Go for loop, break, continue, range
    http://golangtutorials.blog­spot.com/2011/06/control-structures-go-for-loop-break.html
  335. Goroutine IDs
    https://blog.sgmansfield.com/2015/12/go­routine-ids/
  336. Different ways to pass channels as arguments in function in go (golang)
    https://stackoverflow.com/qu­estions/24868859/different-ways-to-pass-channels-as-arguments-in-function-in-go-golang
  337. justforfunc #22: using the Go execution tracer
    https://www.youtube.com/wat­ch?v=ySy3sR1LFCQ
  338. Single Function Exit Point
    http://wiki.c2.com/?Single­FunctionExitPoint
  339. Entry point
    https://en.wikipedia.org/wi­ki/Entry_point
  340. Why does Go have a GOTO statement?!
    https://www.reddit.com/r/go­lang/comments/kag5q/why_do­es_go_have_a_goto_statemen­t/
  341. Effective Go
    https://golang.org/doc/ef­fective_go.html
  342. GoClipse: an Eclipse IDE for the Go programming language
    http://goclipse.github.io/
  343. GoClipse Installation
    https://github.com/GoClip­se/goclipse/blob/latest/do­cumentation/Installation.md#in­stallation
  344. The zero value of a slice is not nil
    https://stackoverflow.com/qu­estions/30806931/the-zero-value-of-a-slice-is-not-nil
  345. Go-tcha: When nil != nil
    https://dev.to/pauljlucas/go-tcha-when-nil–nil-hic
  346. Nils in Go
    https://www.doxsey.net/blog/nils-in-go