Tvorba sešitů pro tabulkové procesory v programovacím jazyku Go – formát xlsx

27. 8. 2020
Doba čtení: 57 minut

Sdílet

Na předchozí článek, v němž jsme se seznámili se základními vlastnostmi knihoven encoding/csv a tealeg/xlsx dnes navážeme. Zaměříme se totiž na popis dalších vlastností formátu Office Open XML Workbook neboli (podle používané koncovky) xlsx i toho, jak tyto vlastnosti ovlivňují tvorbu sešitů.

Obsah

1. Tvorba sešitů pro tabulkové procesory v programovacím jazyku Go – formát xlsx

2. Způsob uložení jednoduchého sešitu s jediným prázdným listem

3. Interní struktura sešitu se třemi prázdnými listy

4. Uložení celočíselných hodnot v buňce sešitu

5. Uložení pravdivostních hodnot a hodnot s plovoucí řádovou čárkou

6. Nepřímé uložení řetězců (referencí)

7. Spojení buněk v tabulce

8. List s horizontálně spojenými buňkami

9. Spojení neexistující buňky

10. Vertikální spojení buněk

11. Specifikace formátu zobrazení hodnot v buňkách

12. Popis stylů zobrazení obsahu buněk

13. Formátování časových údajů a dat

14. Pomocné funkce pro konverzi časových údajů

15. Explicitně nastavené styly zobrazení

16. Závěrem

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

18. Odkazy na Internetu

1. Tvorba sešitů pro tabulkové procesory v programovacím jazyku Go – formát xlsx

V předchozím článku jsme si ukázali, jakým způsobem je možné v aplikacích vyvinutých v programovacím jazyku Go vytvářet takzvané sešity (workbook), které je následně možné otevřít a dále zpracovat v tabulkových procesorech (spreadsheet), například v „kancelářských“ aplikacích Gnumeric, Microsoft Excel, LibreOffice Calc či v některých tabulkových procesorech naprogramovaných a dostupných ve formě webových aplikací (Google Doc, Ethercalc). Nejprve jsme se zaměřili na alespoň stručný popis standardní knihovny encoding/csv, která zajišťuje čtení i zápis tabulek (tedy vlastně jediného listu) uložených ve formátu CSV, přesněji řečeno v podmnožině tohoto variabilního formátu odpovídající RFC 4180. Tato de facto norma však zdaleka nepopisuje všechny varianty CSV, s nimiž se můžeme v praxi setkat. Navíc – což je v praxi ještě problémovější záležitost – se nepopisuje sémantika zápisu informací o datu a/nebo času.

Ve druhé polovině předchozího článku jsme se pak zmínili o knihovně nazvané tealeg/xlsx, která realizuje programové rozhraní k formátu Office Open XML Workbook neboli (podle používané koncovky) xlsx. Tento formát je součástí skupiny formátů známých též pod zkratkou OOXML a – jak uvidíme v dalších kapitolách – vnitřní struktura tohoto formátu je tvořena sadou zazipovaných souborů (většinou používajících jazyk XML). Dnes se seznámíme s některými dalšími vlastnostmi tohoto formátu, protože bez alespoň základní znalosti toho, jaké má xlsx vlastnosti, není možné úspěšně vytvářet složitěji strukturované sešity s množstvím stylů i dalších objektů (grafů atd.).

Poznámka: na tomto místě je možné dobré upozornit na to, že formát xlsx nemá prakticky nic společného s dřívějším binárním formátem xls (což je ostatně jen dobře). Původní xls, který existoval v několika variantách, byl serializačním formátem Excelu, což pochopitelně způsobovalo problémy při přenosu mezi různými verzemi tohoto tabulkového procesoru (nové verze tedy musely explicitně obsahovat kód pro import starších variant). Navíc je zajímavé, že i když je xls binárním formátem, bývala velikost souborů větší než v případě stejných tabulek uložených do xlsx.

2. Způsob uložení jednoduchého sešitu s jediným prázdným listem

Nejprve se podíváme na interní strukturu souboru obsahujícího jednoduchý sešit s jediným prázdným listem. Jedná se tedy o nejjednodušší možný sešit vůbec, protože již minule jsme se dozvěděli, že každý sešit musí obsahovat alespoň jeden list (což je dosti podobná vlastnost, jakou mají textové procesory, u nichž nejjednodušší dokument taktéž obsahuje minimálně jednu prázdnou stranu). Sešit s jediným prázdným listem je pochopitelně možné vytvořit v prakticky jakémkoli moderním tabulkovém procesoru, ovšem my si ukážeme programové vytvoření (to má velkou přednost v tom, že výsledný xlsx bude „čistý“: nebude obsahovat mnoho nadbytečných informací). V případě programové tvorby sešitu se nejedná o žádné nové operace, protože jsme se s nimi seznámili již v předchozím článku. Zdrojový kód programu, který takový sešit vytvoří, může vypadat následovně:

package main
 
import (
        "fmt"
 
        "github.com/tealeg/xlsx/v3"
)
 
// jméno generovaného souboru
const spreadsheetName = "test02.xlsx"
 
func main() {
        // konstrukce struktury typu File
        worksheet := xlsx.NewFile()
 
        fmt.Println(worksheet)
 
        // přidání listu do sešitu
        sheet, err := worksheet.AddSheet("Tabulka1")
        if err != nil {
                panic(err)
        }
 
        fmt.Println(sheet)
 
        // pokus o uložení sešitu
        err = worksheet.Save(spreadsheetName)
        if err != nil {
                panic(err)
        }
}

Po překladu a spuštění této aplikace by měl vzniknout soubor nazvaný test02.xlsx o velikosti 5651 bajtů. To lze snadno ověřit:

$ ls -l test02.xlsx
 
-rw-rw-r--. 1 ptisnovs ptisnovs 5651 Aug 25 19:21 test02.xlsx

Mohlo by se zdát, že prakticky prázdný sešit by mohl mít i menší velikost (v případě CSV by se jednalo o soubor o velikosti přesně nula bajtů), ovšem ve skutečnosti roste velikost souboru se zvětšujícími se tabulkami poměrně rozumným způsobem. I v souboru s prázdným sešitem je totiž nutné mít uloženy metainformace, styly atd. Jak jsme si již naznačili v úvodní kapitole, jsou soubory s koncovkou .xlsx de facto zazipované adresářové struktury s množstvím dalších souborů (jejich počet se mění se složitostí sešitu). Můžeme si to ostatně ověřit, protože obsah zazipovaného archivu snadno získáme nástrojem unzip:

$ unzip -l test02.xlsx
 
Archive:  test02.xlsx
  Length      Date    Time    Name
---------  ---------- -----   ----
      798  00-00-1980 00:00   xl/worksheets/sheet1.xml
      743  00-00-1980 00:00   xl/workbook.xml
      580  00-00-1980 00:00   _rels/.rels
      308  00-00-1980 00:00   docProps/app.xml
      364  00-00-1980 00:00   docProps/core.xml
    10940  00-00-1980 00:00   xl/theme/theme1.xml
      142  00-00-1980 00:00   xl/sharedStrings.xml
      736  00-00-1980 00:00   xl/_rels/workbook.xml.rels
     1485  00-00-1980 00:00   [Content_Types].xml
     1062  00-00-1980 00:00   xl/styles.xml
---------                     -------
    17158                     10 files
Poznámka: povšimněte si zcela jistě špatného data vzniku/modifikace souborů uvnitř archivu.

Z výše uvedených deseti souborů nás bude zajímat jen mnohem menší podmnožina. Zejména se jedná o soubor nazvaný workbook.xml, který obsahuje popis struktury celého sešitu. Již podle koncovky je patrné, že se jedná o soubor s daty reprezentovanými v jazyku XML, ovšem soubor je minifikován a není tak příliš čitelný. Z tohoto důvodu provedeme jeho naformátování, a to například nástrojem xmllint:

$ xmllint --format workbook.xml

Výsledek by měl vypadat následovně:

<?xml version="1.0" encoding="UTF-8"?>
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <fileVersion appName="Go XLSX"/>
  <workbookPr showObjects="all" date1904="false"/>
  <workbookProtection/>
  <bookViews>
    <workbookView showHorizontalScroll="true" showVerticalScroll="true" showSheetTabs="true" tabRatio="204" windowHeight="8192" windowWidth="16384" xWindow="0" yWindow="0"/>
  </bookViews>
  <sheets>
    <sheet name="Tabulka1" sheetId="1" r:id="rId1" state="visible"/>
  </sheets>
  <definedNames/>
  <calcPr iterateCount="100" refMode="A1" iterateDelta="0.001"/>
</workbook>

Povšimněte si, že kromě informací o způsobu zobrazení sešitu je v tomto souboru uvedena jediná další důležitá informace – název jediného listu „Tabulka1“ a identifikátor tohoto listu „1“.

Poznámka: i když je identifikátor celým číslem, musí být uveden v uvozovkách, neboť toto je požadavek platný pro všechny atributy v jazyce XML.

Druhým důležitým souborem je soubor nazvaný sheet1.xml. Ten obsahuje popis listu s ID=1, takže se opět podívejme, jaké informace lze z tohoto souboru získat:

$ xmllint --format sheet1.xml

Výsledek by měl po naformátování vypadat následovně:

<?xml version="1.0" encoding="UTF-8"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <sheetPr filterMode="false">
    <pageSetUpPr fitToPage="false"/>
  </sheetPr>
  <dimension ref="A1"/>
  <sheetViews>
    <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0">
      <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/>
    </sheetView>
  </sheetViews>
  <sheetFormatPr defaultRowHeight="12.85"/>
  <sheetData/>
</worksheet>

Vzhledem k tomu, že je sešit prázdný, obsahuje soubor sheet1.xml pouze informace o způsobu jeho zobrazení (sheetViews), zatímco uzel s daty je prázdný (sheetData).

Poznámka: jak jste prozatím mohli vidět, naprostá většina informací se týká způsobu zobrazení sešitu, popř. jednotlivých listů v tabulkovém procesoru. Tyto údaje knihovna xlsx generuje automaticky a pouze některé z nich je možné explicitně specifikovat. S podrobnostmi se seznámíme v dalším textu.

3. Interní struktura sešitu se třemi prázdnými listy

Dále prozkoumáme interní strukturu sešitu, který obsahuje trojici prázdných listů, přičemž jednotlivé listy jsou nazvány „Tabulka1“, „Tabulka2“ a „Tabulka3“. Takový sešit lze vytvořit například následujícím programem, který již byl (podobně jako program z předchozí kapitoly) prezentován minule:

package main
 
import (
        "fmt"
 
        "github.com/tealeg/xlsx/v3"
)
 
// jméno generovaného souboru
const spreadsheetName = "test03.xlsx"
 
func main() {
        // konstrukce struktury typu File
        worksheet := xlsx.NewFile()
 
        fmt.Println(worksheet)
 
        // přidání tří listů do sešitu
        names := []string{"Tabulka1", "Tabulka2", "Tabulka3"}
        for _, name := range names {
                // pokus o přidání nového listu
                sheet, err := worksheet.AddSheet(name)
                if err != nil {
                        panic(err)
                }
 
                fmt.Println(sheet)
        }
 
        // pokus o uložení sešitu
        err := worksheet.Save(spreadsheetName)
        if err != nil {
                panic(err)
        }
}

Podle předpokladů bude nyní soubor s koncovkou .xlsx obsahovat nikoli pouze deset souborů, ale souborů dvanáct, protože každý list je v archivu reprezentován samostatným souborem (což je poměrně dobré uspořádání):

$ unzip -l test03.xlsx
 
Archive:  test03.xlsx
  Length      Date    Time    Name
---------  ---------- -----   ----
      798  00-00-1980 00:00   xl/worksheets/sheet1.xml
      799  00-00-1980 00:00   xl/worksheets/sheet2.xml
      799  00-00-1980 00:00   xl/worksheets/sheet3.xml
      885  00-00-1980 00:00   xl/workbook.xml
      580  00-00-1980 00:00   _rels/.rels
      308  00-00-1980 00:00   docProps/app.xml
      364  00-00-1980 00:00   docProps/core.xml
    10940  00-00-1980 00:00   xl/theme/theme1.xml
      142  00-00-1980 00:00   xl/sharedStrings.xml
     1046  00-00-1980 00:00   xl/_rels/workbook.xml.rels
     1777  00-00-1980 00:00   [Content_Types].xml
     1062  00-00-1980 00:00   xl/styles.xml
---------                     -------
    19500                     12 files

Soubor obsahující popis sešitu nyní obsahuje informaci o třech listech, přičemž každému listu je přiřazen jednoznačný identifikátor, který se objevuje i ve jménu souboru s obsahem listu. Viz též zvýrazněné atributy; první s názvem listu a druhý s jeho identifikátorem (to však neznamená, že názvy listů mohou být totožné!):

$ xmllint --format workbook.xml
 
<?xml version="1.0" encoding="UTF-8"?>
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <fileVersion appName="Go XLSX"/>
  <workbookPr showObjects="all" date1904="false"/>
  <workbookProtection/>
  <bookViews>
    <workbookView showHorizontalScroll="true" showVerticalScroll="true" showSheetTabs="true" tabRatio="204" windowHeight="8192" windowWidth="16384" xWindow="0" yWindow="0"/>
  </bookViews>
  <sheets>
    <sheet name="Tabulka1" sheetId="1" r:id="rId1" state="visible"/>
    <sheet name="Tabulka2" sheetId="2" r:id="rId2" state="visible"/>
    <sheet name="Tabulka3" sheetId="3" r:id="rId3" state="visible"/>
  </sheets>
  <definedNames/>
  <calcPr iterateCount="100" refMode="A1" iterateDelta="0.001"/>
</workbook>
Poznámka: obsah souborů sheet1.xml, sheet2.xml a sheet3.xml si nemusíme ukazovat, protože se nijak nezměnil oproti předchozímu demonstračnímu příkladu s jediným listem.

4. Uložení celočíselných hodnot v buňce sešitu

V dalším demonstračním příkladu si ukážeme, jakým způsobem jsou uloženy celočíselné hodnoty v buňce sešitu. Nejprve si ukažme zdrojový kód příkladu, po jehož spuštění se vytvoří soubor se sešitem obsahujícím jediný list, který obsahuje jedinou buňku naplněnou celočíselnou hodnotou 42 (nikoli tedy řetězcem „42“):

package main
 
import (
        "fmt"
 
        "github.com/tealeg/xlsx/v3"
)
 
// jméno generovaného souboru
const spreadsheetName = "test13.xlsx"
 
func main() {
        // konstrukce struktury typu File
        worksheet := xlsx.NewFile()
 
        fmt.Println(worksheet)
 
        // přidání listu do sešitu
        sheet, err := worksheet.AddSheet("Tabulka1")
        if err != nil {
                panic(err)
        }
        defer sheet.Close()
 
        fmt.Println(sheet)
 
        // přidání řádku do tabulky
        row := sheet.AddRow()
 
        // přidání buňky na řádek
        cell := row.AddCell()
 
        // naplnění buňky hodnotou
        cell.SetInt(42)
 
        // pokus o uložení sešitu
        err = worksheet.Save(spreadsheetName)
        if err != nil {
                panic(err)
        }
}

Zajímat nás bude pouze obsah souboru sheet1.xml s obsahem listu, takže si ho zobrazíme ve formátované podobě:

$ xmllint --format sheet1.xml

Vypsat by se měl následující naformátovaný obsah:

<?xml version="1.0" encoding="UTF-8"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <sheetPr filterMode="false">
    <pageSetUpPr fitToPage="false"/>
  </sheetPr>
  <dimension ref="A1"/>
  <sheetViews>
    <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0">
      <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/>
    </sheetView>
  </sheetViews>
  <sheetFormatPr defaultRowHeight="12.85"/>
  <sheetData>
    <row r="1">
      <c r="A1">
        <v>42</v>
      </c>
    </row>
  </sheetData>
</worksheet>

Důležité informace jsou zvýrazněny tučným písmem, takže jen ve stručnosti:

  1. Hodnoty, které jsou na list vloženy, jsou umístěny do uzlu nazvanéhosheetData.
  2. Neukládají se přímo jednotlivé buňky, ale řádky tabulky, přičemž každý řádek je umístěn v samostatném uzlu nazvaném row s identifikátorem (což je celé číslo vetší nebo rovno jedné – pouze některé starší tabulkové procesory číslují řádky od nuly).
  3. Samotná buňka je představována uzlem nazvaným c, který opět obsahuje svoji adresu; v našem případě A1.
  4. Hodnota umístěná do buňky je uložena v uzlu nazvanémv. V případě celočíselné hodnoty je v uzlu přímo tato hodnota. Zajímavé je, že u celočíselných hodnot se neuvádí typ, pouze je v uzlu v umístěna hodnota 42 bez dalších doplňujících metainformací.
Poznámka: povšimněte si, že pro velmi často se opakující uzly, tedy pro jednotlivé buňky a jejich obsah (hodnoty), se používají pouze jednopísmenné názvy uzlů. Jedná se o snahu o zmenšení velikosti výsledného souboru, což je poměrně rozumný přístup. Pochopitelně to nemůže konkurovat formátům CSV nebo TSV, ovšem doména použití těchto formátů se s OOXML překrývá pouze částečně.

5. Uložení pravdivostních hodnot a hodnot s plovoucí řádovou čárkou

Víme již, jak jsou uloženy buňky obsahující celá čísla, takže logicky zbývá odpovědět na otázku uložení pravdivostních hodnot, popř. numerických hodnot s řádovou čárkou (nutně se nemusí jednat o plovoucí čárku!). Sešit s listem obsahujícím pravdivostní hodnotu a číslo 1/3 vytvoříme spuštěním následujícího demonstračního příkladu:

package main
 
import (
        "fmt"
 
        "github.com/tealeg/xlsx/v3"
)
 
// jméno generovaného souboru
const spreadsheetName = "test14.xlsx"
 
func main() {
        // konstrukce struktury typu File
        worksheet := xlsx.NewFile()
 
        fmt.Println(worksheet)
 
        // přidání listu do sešitu
        sheet, err := worksheet.AddSheet("Tabulka1")
        if err != nil {
                panic(err)
        }
        defer sheet.Close()
 
        fmt.Println(sheet)
 
        // přidání řádku do tabulky
        row := sheet.AddRow()
 
        // přidání buňky na řádek
        cell := row.AddCell()
 
        // naplnění buňky hodnotou
        cell.SetFloat(1 / 3.)
 
        // přidání buňky na řádek
        cell = row.AddCell()
 
        // naplnění buňky hodnotou
        cell.SetBool(false)
 
        // přidání buňky na řádek
        cell = row.AddCell()
 
        // naplnění buňky hodnotou
        cell.SetBool(true)
 
        // pokus o uložení sešitu
        err = worksheet.Save(spreadsheetName)
        if err != nil {
                panic(err)
        }
}

Opět nás bude zajímat pouze obsah souboru sheet1.xml s informacemi o jediném listu, který se v sešitu nachází:

$ xmllint --format sheet1.xml

Výsledky jsou nyní zajímavější, protože ukazují, že:

  1. Hodnota s řádovou čárkou je uložena v největší podporované přesnosti, a to opět bez uvedení datového typu (rozlišení mezi celými čísly a čísly s řádovou čárkou je tedy implicitní).
  2. Pravdivostní hodnota je převedena na celé číslo, a to true → 1 a false → 0 (tedy pro nás programátory typickým způsobem).
  3. U pravdivostních hodnot je uveden typ t=„b“, takže tabulkové procesory budou umět hodnoty 0 a 1 správně interpretovat.

Ověřme si, že jsou tato tvrzení skutečně správná, a to pohledem do souboru sheet1.xml:

<?xml version="1.0" encoding="UTF-8"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <sheetPr filterMode="false">
    <pageSetUpPr fitToPage="false"/>
  </sheetPr>
  <dimension ref="A1:B1"/>
  <sheetViews>
    <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0">
      <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/>
    </sheetView>
  </sheetViews>
  <sheetFormatPr defaultRowHeight="12.85"/>
  <sheetData>
    <row r="1">
      <c r="A1">
        <v>0.3333333333333333</v>
      </c>
      <c r="B1" t="b">
        <v>0</v>
      </c>
      <c r="C1" t="b">
        <v>1</v>
      </c>
    </row>
  </sheetData>
</worksheet>

6. Nepřímé uložení řetězců (referencí)

Nyní zdrojový kód demonstračního příkladu, který vytváří sešit, nepatrně upravíme, a to konkrétně takovým způsobem, aby se v listu sešitu nacházela buňka s řetězcem (použijeme tedy metodu SetString). Jak totiž uvidíme dále, jsou řetězce ukládány způsobem zcela odlišným od „primitivních“ hodnot, což může být zpočátku překvapující:

package main
 
import (
        "fmt"
 
        "github.com/tealeg/xlsx/v3"
)
 
// jméno generovaného souboru
const spreadsheetName = "test04.xlsx"
 
func main() {
        // konstrukce struktury typu File
        worksheet := xlsx.NewFile()
 
        fmt.Println(worksheet)
 
        // přidání listu do sešitu
        sheet, err := worksheet.AddSheet("Tabulka1")
        if err != nil {
                panic(err)
        }
        defer sheet.Close()
 
        fmt.Println(sheet)
 
        // přidání řádku do tabulky
        row := sheet.AddRow()
 
        // přidání buňky na řádek
        cell := row.AddCell()
 
        // naplnění buňky hodnotou
        cell.SetString("Hello")
 
        // pokus o uložení sešitu
        err = worksheet.Save(spreadsheetName)
        if err != nil {
                panic(err)
        }
}

Pohled na interní strukturu sešitu nám odhalí, jak jsou řetězce ukládány:

$ xmllint --format sheet1.xml

Z výpisu je patrné, že list obsahuje jedinou buňku (konkrétně buňku A1), která je typu „s“ a obsahuje hodnotu 0. To je zajisté zvláštní, protože jsme přece do listu uložili řetězec „Hello“ a nikoli nulovou hodnotu:

<?xml version="1.0" encoding="UTF-8"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <sheetPr filterMode="false">
    <pageSetUpPr fitToPage="false"/>
  </sheetPr>
  <dimension ref="A1"/>
  <sheetViews>
    <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0">
      <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/>
    </sheetView>
  </sheetViews>
  <sheetFormatPr defaultRowHeight="12.85"/>
  <sheetData>
    <row r="1">
      <c r="A1" t="s">
        <v>0</v>
      </c>
    </row>
  </sheetData>
</worksheet>

Ve skutečnosti jsou řetězce ukládány do jiného souboru nazvaného sharedStrings.xml ve formě jednoduché tabulky:

$ xmllint --format sharedStrings.xml
 
<?xml version="1.0" encoding="UTF-8"?>
<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="1" uniqueCount="1">
  <si>
    <t>Hello</t>
  </si>
</sst>

Tabulkový procesor z této tabulky přečte řetězec s indexem 0 a zobrazí ho v buňce A1.

Poznámka: do určité míry tento přístup připomíná string pool, s nímž jsme se seznámili při popisu interní struktury souborů class.

7. Spojení buněk v tabulce

Tabulky používané v tabulkových procesorech nejsou čistými maticemi buněk o stejné velikosti. Buňky, přesněji řečeno sousední buňky tvořící obdélníkové oblasti, je totiž možné spojovat. V knihovně tealeg/xlsx k tomuto účelu slouží metoda nazvaná Merge aplikovaná na buňku – to nám napovídá, že spojení je vlastností buňky a nikoli sešitu:

$ go doc tealeg/xlsx.Merge
 
package xlsx // import "github.com/tealeg/xlsx"
 
func (c *Cell) Merge(hcells, vcells int)
    Merge with other cells, horizontally and/or vertically.

Z popisu je patrné, že se této funkci předává dvojice celých čísel. Tyto hodnoty udávají s kolika buňkami horizontálně, popř. vertikálně se má buňka spojit. To znamená, že číslo 1 znamená spojení se sousední buňkou, zatímco číslo 0 znamená, že v daném směru ke spojení nedochází (to je velký rozdíl například oproti atributům rowspan a colspan v HTML). A dalším rozdílem je, že spojované buňky by měly v listu existovat, jinak může při importu sešitu dojít k chybě (to si ostatně ukážeme v dalších kapitolách).

Poznámka: tato funkcionalita není dostupná ve formátu CSV, který sešity skutečně reprezentuje jako pravidelné matice (i když je pravda, že jednotlivé řádky mohou mít rozdílný počet buněk).

8. List s horizontálně spojenými buňkami

V následujícím demonstračním příkladu je vytvořen sešit s jedním listem a tento list obsahuje trojici buněk (všechny na jednom řádku). Ovšem druhá buňka je spojena s buňkou třetí, takže ve skutečnosti hodnotu třetí buňky v tabulkovém procesoru neuvidíme, což je ostatně patrné i na screenshotu:

package main
 
import (
        "fmt"

        "github.com/tealeg/xlsx/v3"
)
 
// jméno generovaného souboru
const spreadsheetName = "test15.xlsx"
 
func main() {
        // konstrukce struktury typu File
        worksheet := xlsx.NewFile()
 
        fmt.Println(worksheet)
 
        // přidání listu do sešitu
        sheet, err := worksheet.AddSheet("Tabulka1")
        if err != nil {
                panic(err)
        }
        defer sheet.Close()
 
        fmt.Println(sheet)
 
        // přidání řádku do tabulky
        row := sheet.AddRow()
 
        // přidání první buňky na řádek
        cell := row.AddCell()
 
        // naplnění buňky hodnotou
        cell.SetString("1x1")
 
        // přidání druhé buňky na řádek
        cell = row.AddCell()
 
        // naplnění buňky hodnotou
        cell.SetString("2x1")
 
        // a spojení s další buňkou
        cell.Merge(1, 0)
 
        // přidání třetí buňky na řádek
        cell = row.AddCell()
 
        // naplnění buňky hodnotou
        cell.SetString("1x1")
 
        // pokus o uložení sešitu
        err = worksheet.Save(spreadsheetName)
        if err != nil {
                panic(err)
        }
}

Zajímavé bude zjistit, jak se vlastně informace o spojení buněk uloží do souboru sheet1.xml s popisem obsahu listu:

$ xmllint --format sheet1.xml 
 
<?xml version="1.0" encoding="UTF-8"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <sheetPr filterMode="false">
    <pageSetUpPr fitToPage="false"/>
  </sheetPr>
  <dimension ref="A1:C1"/>
  <sheetViews>
    <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0">
      <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/>
    </sheetView>
  </sheetViews>
  <sheetFormatPr defaultRowHeight="12.85"/>
  <sheetData>
    <row r="1">
      <c r="A1" t="s">
        <v>0</v>
      </c>
      <c r="B1" t="s">
        <v>1</v>
      </c>
      <c r="C1" t="s">
        <v>0</v>
      </c>
    </row>
  </sheetData>
  <mergeCells count="1">
    <mergeCell ref="B1:C1"/>
  </mergeCells>
</worksheet>

Můžeme vidět, že informace o spojených buňkách není součástí atributu buňky (jak by nás k tomu mohla vést metoda Merge), ale „globální informací“ vztaženou k celému listu.

Poznámka: sdílené řetězce s indexy 0 a 1 jsou opět uloženy v souboru sharedStrings.xml, kde je patrné, že řetězec se shodným obsahem je uložen jen jedenkrát:
$ xmllint --format sharedStrings.xml 
 
<?xml version="1.0" encoding="UTF-8"?>
<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="2" uniqueCount="2">
  <si>
    <t>1x1</t>
  </si>
  <si>
    <t>2x1</t>
  </si>
</sst>

9. Spojení neexistující buňky

V předchozí kapitole jsme si řekli, že pokud dochází ke spojení buněk, musí i další spojované buňky existovat, i když se jejich hodnota ani styl nikde nezobrazí. Pokud tomu tak není, mohou tabulkové procesory nahlásit chybu při pokusu o import takto upraveného sešitu:

Sešit se špatným obsahem byl vytvořen tímto demonstračním příkladem (který ovšem po svém spuštění žádnou chybu nenahlásí):

package main
 
import (
        "fmt"

        "github.com/tealeg/xlsx/v3"
)
 
// jméno generovaného souboru
const spreadsheetName = "test16.xlsx"
 
func main() {
        // konstrukce struktury typu File
        worksheet := xlsx.NewFile()
 
        fmt.Println(worksheet)
 
        // přidání listu do sešitu
        sheet, err := worksheet.AddSheet("Tabulka1")
        if err != nil {
                panic(err)
        }
        defer sheet.Close()
 
        fmt.Println(sheet)
 
        // přidání řádku do tabulky
        row := sheet.AddRow()
 
        // přidání první buňky na řádek
        cell := row.AddCell()
 
        // naplnění buňky hodnotou
        cell.SetString("1x1")
 
        // přidání druhé buňky na řádek
        cell = row.AddCell()
 
        // naplnění buňky hodnotou
        cell.SetString("2x1")
 
        // a spojení s další buňkou
        cell.Merge(1, 0)
 
        // pokus o uložení sešitu
        err = worksheet.Save(spreadsheetName)
        if err != nil {
                panic(err)
        }
}

10. Vertikální spojení buněk

V případě, že se buňky spojují vertikálně (tedy mezi několika řádky), musí být všechny spojované řádky explicitně vytvořeny, což si na nejjednodušším příkladu (spojení dvou buněk pod sebou) ukážeme v následujícím zdrojovém kódu. Povšimněte si (zvýrazněný řádek), jak je možné jediným příkazem zajistit vytvoření nového řádku, přidání buňky na tento řádek a současně i nastavení hodnoty buňky:

package main
 
import (
        "fmt"
 
        "github.com/tealeg/xlsx/v3"
)
 
// jméno generovaného souboru
const spreadsheetName = "test17.xlsx"
 
func main() {
        // konstrukce struktury typu File
        worksheet := xlsx.NewFile()
 
        fmt.Println(worksheet)
 
        // přidání listu do sešitu
        sheet, err := worksheet.AddSheet("Tabulka1")
        if err != nil {
                panic(err)
        }
        defer sheet.Close()
 
        fmt.Println(sheet)
 
        // přidání řádku do tabulky
        row := sheet.AddRow()
 
        // přidání první buňky na řádek
        cell := row.AddCell()
 
        // naplnění buňky hodnotou
        cell.SetString("1x2")
 
        // naplnění buňky hodnotou
        cell.SetString("1x2")
 
        // a spojení s buňkou na následujícím řádku
        cell.Merge(0, 1)
 
        // přidání druhé buňky na řádek
        cell = row.AddCell()
 
        // naplnění buňky hodnotou
        cell.SetString("1x1")
 
        // další řádek tabulky
        sheet.AddRow().AddCell().SetString("foobar")
 
        // pokus o uložení sešitu
        err = worksheet.Save(spreadsheetName)
        if err != nil {
                panic(err)
        }
}

Výsledek by mohl po otevření v tabulkovém procesoru vypadat následovně:

Nyní v souboru sheet1.xml nalezneme mj. i následující informaci o spojení buněk:

  <mergeCells count="1">
    <mergeCell ref="A1:A2"/>
  </mergeCells>

11. Specifikace formátu zobrazení hodnot v buňkách

Tabulkové procesory rozlišují mezi hodnotou buňky (což může být i vzorec) a zobrazenou hodnotou. Po textově-grafické stránce se tyto dva údaje mohou odlišovat a mnohdy se i odlišují, protože v mnoha případech například požadujeme zobrazení pouze určitého počtu desetinných míst, určitý konkrétní způsob zobrazení časových údajů atd. Následující demonstrační příklad již známe, protože jsme se s ním seznámili minule. Ukazuje, jakým způsobem se nastavuje formát zobrazení numerických hodnot s řádovou čárkou (hodnota je ve všech buňkách stejná, ovšem zobrazí se různým způsobem):

package main
 
import (
        "fmt"
 
        "github.com/tealeg/xlsx/v3"
)
 
// jméno generovaného souboru
const spreadsheetName = "test07.xlsx"
 
func main() {
        // konstrukce struktury typu File
        worksheet := xlsx.NewFile()
 
        fmt.Println(worksheet)
 
        // přidání listu do sešitu
        sheet, err := worksheet.AddSheet("Tabulka1")
        if err != nil {
                panic(err)
        }
        defer sheet.Close()
 
        fmt.Println(sheet)
 
        // přidání řádku do tabulky
        row := sheet.AddRow()
 
        // přidání buňky na řádek a naplnění hodnotou
        row.AddCell().SetFloatWithFormat(1/3.0, "#0")
        row.AddCell().SetFloatWithFormat(1/3.0, "#0.0")
        row.AddCell().SetFloatWithFormat(1/3.0, "#0.00")
        row.AddCell().SetFloatWithFormat(1/3.0, "#0.000")
        row.AddCell().SetFloatWithFormat(1/3.0, "#0.0000")
        row.AddCell().SetFloatWithFormat(1/3.0, "#0.00000")
        row.AddCell().SetFloatWithFormat(1/3.0, "#0.000000")
 
        // pokus o uložení sešitu
        err = worksheet.Save(spreadsheetName)
        if err != nil {
                panic(err)
        }
}

V samotném sešitu je hodnota uložena v plné (dostupné) přesnosti, což je ostatně patrné i z pohledu na zdrojový kód sešitu. Ovšem u buněk je navíc ještě specifikován index stylu (zvýrazněný atribut):

$ xmllint --format sheet1.xml
 
<?xml version="1.0" encoding="UTF-8"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <sheetPr filterMode="false">
    <pageSetUpPr fitToPage="false"/>
  </sheetPr>
  <dimension ref="A1:G1"/>
  <sheetViews>
    <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0">
      <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/>
    </sheetView>
  </sheetViews>
  <sheetFormatPr defaultRowHeight="12.85"/>
  <sheetData>
    <row r="1">
      <c r="A1" s="1">
        <v>0.3333333333333333</v>
      </c>
      <c r="B1" s="2">
        <v>0.3333333333333333</v>
      </c>
      <c r="C1" s="3">
        <v>0.3333333333333333</v>
      </c>
      <c r="D1" s="4">
        <v>0.3333333333333333</v>
      </c>
      <c r="E1" s="5">
        <v>0.3333333333333333</v>
      </c>
      <c r="F1" s="6">
        <v>0.3333333333333333</v>
      </c>
      <c r="G1" s="7">
        <v>0.3333333333333333</v>
      </c>
    </row>
  </sheetData>
</worksheet>

12. Popis stylů zobrazení obsahu buněk

Styly zobrazení jsou uloženy v samostatném souboru nazvaném styles.xml, jehož struktura je poměrně komplikovaná. Ovšem můžeme zde vidět především sedm specifikací zobrazení numerických hodnot:

<numFmts count="7">
  <numFmt numFmtId="164" formatCode="#0"/>
  <numFmt numFmtId="165" formatCode="#0.0"/>
  <numFmt numFmtId="166" formatCode="#0.00"/>
  <numFmt numFmtId="167" formatCode="#0.000"/>
  <numFmt numFmtId="168" formatCode="#0.0000"/>
  <numFmt numFmtId="169" formatCode="#0.00000"/>
  <numFmt numFmtId="170" formatCode="#0.000000"/>
</numFmts>

Ty jsou referencovány ve specifikaci stylů buněk. Příkladem může být druhý styl, který používá zobrazení numerických hodnot popsané formátovacím řetězcem „#0“:

<cellXfs count="8">
  ...
  ...
  ...
  <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="164">
    <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/>
  </xf>
  ...
  ...
  ...
  </cellXfs>

Pro úplnost si ukažme úplný obsah souboru s popisem stylů:

<?xml version="1.0" encoding="UTF-8"?>
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
  <numFmts count="7">
    <numFmt numFmtId="164" formatCode="#0"/>
    <numFmt numFmtId="165" formatCode="#0.0"/>
    <numFmt numFmtId="166" formatCode="#0.00"/>
    <numFmt numFmtId="167" formatCode="#0.000"/>
    <numFmt numFmtId="168" formatCode="#0.0000"/>
    <numFmt numFmtId="169" formatCode="#0.00000"/>
    <numFmt numFmtId="170" formatCode="#0.000000"/>
  </numFmts>
  <fonts count="1">
    <font>
      <sz val="11"/>
      <name val="Arial"/>
      <family val="2"/>
      <color theme="1"/>
      <scheme val="minor"/>
    </font>
  </fonts>
  <fills count="2">
    <fill>
      <patternFill patternType="none"/>
    </fill>
    <fill>
      <patternFill patternType="gray125"/>
    </fill>
  </fills>
  <borders count="1">
    <border>
      <left/>
      <right/>
      <top/>
      <bottom/>
    </border>
  </borders>
  <cellStyleXfs count="1">
    <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="0" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="0">
      <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/>
    </xf>
  </cellStyleXfs>
  <cellXfs count="8">
    <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="0" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="0">
      <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/>
    </xf>
    <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="164">
      <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/>
    </xf>
    <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="165">
      <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/>
    </xf>
    <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="166">
      <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/>
    </xf>
    <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="167">
      <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/>
    </xf>
    <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="168">
      <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/>
    </xf>
    <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="169">
      <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/>
    </xf>
    <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="1" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="170">
      <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/>
    </xf>
  </cellXfs>
</styleSheet>

13. Formátování časových údajů a dat

V běžných tabulkách se velmi často pracuje s časovými údaji a pravděpodobně ještě častěji s daty (resp. s kombinací datum+čas). Tyto údaje, které jsou interně reprezentovány číslem s řádovou čárkou, je možné zobrazit mnoha různými způsoby, které jsou specifikovány formátovacím řetězcem. Ukažme si použití následujících formátů, kde „y“ představuje rok, „m“ měsíc, „d“ den atd.:

"yyyy-mm-dd"
"m/d"
"m/d/yyyy"
"dd/mm/yyyy"
"dd/mm/yy"
"yyyy-mm-dd hh:mm:ss"
"hh:mm"
"hh:mm:ss"
"h:mm:ss"
"[h]:mm:ss"
"[mm]:ss"
Poznámka: časové údaje ve druhém sloupci jsou shodné, jen jsou pokaždé zobrazeny jiným způsobem.

V následujícím demonstračním příkladu je ukázáno, jak lze nastavit styl zobrazení buněk s časovými údaji (což vlastně znamená přiřazení formátovacího řetězce buňce):

package main
 
import (
        "fmt"
        "time"
 
        "github.com/tealeg/xlsx/v3"
)
 
// jméno generovaného souboru
const spreadsheetName = "test12.xlsx"
 
func main() {
        // konstrukce struktury typu File
        worksheet := xlsx.NewFile()
 
        fmt.Println(worksheet)
 
        // přidání listu do sešitu
        sheet, err := worksheet.AddSheet("Tabulka1")
        if err != nil {
                panic(err)
        }
        defer sheet.Close()
 
        fmt.Println(sheet)
 
        // formáty časového razítka, které si odzkoušíme
        formats := []string{
                "yyyy-mm-dd",
                "m/d",
                "m/d/yyyy",
                "dd/mm/yyyy",
                "dd/mm/yy",
                "yyyy-mm-dd hh:mm:ss",
                "hh:mm",
                "hh:mm:ss",
                "h:mm:ss",
                "[h]:mm:ss",
                "[mm]:ss",
        }
 
        // aktuální datum a čas
        timestamp := time.Now()
 
        // zobrazit tabulku s daty/časy naformátovanými zvoleným formátem
        for _, format := range formats {
                // přidání nového řádku do tabulky
                row := sheet.AddRow()
 
                // popis formátu
                row.AddCell().SetString(format)
 
                // naformátované časové razítko
                cell := row.AddCell()
                cell.SetDateTime(timestamp)
                cell.SetFormat(format)
        }
 
        // pokus o uložení sešitu
        err = worksheet.Save(spreadsheetName)
        if err != nil {
                panic(err)
        }
}

Z obsahu souboru sheet1.xml je patrné, že hodnoty ve druhém sloupci jsou skutečně shodné, ovšem odkaz na styl je pokaždé odlišný:

<?xml version="1.0" encoding="UTF-8"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <sheetPr filterMode="false">
    <pageSetUpPr fitToPage="false"/>
  </sheetPr>
  <dimension ref="A1:B11"/>
  <sheetViews>
    <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0">
      <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/>
    </sheetView>
  </sheetViews>
  <sheetFormatPr defaultRowHeight="12.85"/>
  <sheetData>
    <row r="1">
      <c r="A1" t="s">
        <v>0</v>
      </c>
      <c r="B1" s="1">
        <v>44069.7353125</v>
      </c>
    </row>
    <row r="2">
      <c r="A2" t="s">
        <v>1</v>
      </c>
      <c r="B2" s="2">
        <v>44069.7353125</v>
      </c>
    </row>
    <row r="3">
      <c r="A3" t="s">
        <v>2</v>
      </c>
      <c r="B3" s="3">
        <v>44069.7353125</v>
      </c>
    </row>
    <row r="4">
      <c r="A4" t="s">
        <v>3</v>
      </c>
      <c r="B4" s="4">
        <v>44069.7353125</v>
      </c>
    </row>
    <row r="5">
      <c r="A5" t="s">
        <v>4</v>
      </c>
      <c r="B5" s="5">
        <v>44069.7353125</v>
      </c>
    </row>
    <row r="6">
      <c r="A6" t="s">
        <v>5</v>
      </c>
      <c r="B6" s="6">
        <v>44069.7353125</v>
      </c>
    </row>
    <row r="7">
      <c r="A7" t="s">
        <v>6</v>
      </c>
      <c r="B7" s="7">
        <v>44069.7353125</v>
      </c>
    </row>
    <row r="8">
      <c r="A8" t="s">
        <v>7</v>
      </c>
      <c r="B8" s="8">
        <v>44069.7353125</v>
      </c>
    </row>
    <row r="9">
      <c r="A9" t="s">
        <v>8</v>
      </c>
      <c r="B9" s="9">
        <v>44069.7353125</v>
      </c>
    </row>
    <row r="10">
      <c r="A10" t="s">
        <v>9</v>
      </c>
      <c r="B10" s="10">
        <v>44069.7353125</v>
      </c>
    </row>
    <row r="11">
      <c r="A11" t="s">
        <v>10</v>
      </c>
      <c r="B11" s="11">
        <v>44069.7353125</v>
      </c>
    </row>
  </sheetData>
</worksheet>

Začátek obsahu souboru styles.xml se specifikací formátovacích řetězců:

$ xmllint --format styles.xml
 
<?xml version="1.0" encoding="UTF-8"?>
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
  <numFmts count="9">
    <numFmt numFmtId="164" formatCode="yyyy-mm-dd"/>
    <numFmt numFmtId="165" formatCode="m/d"/>
    <numFmt numFmtId="166" formatCode="m/d/yyyy"/>
    <numFmt numFmtId="167" formatCode="dd/mm/yyyy"/>
    <numFmt numFmtId="168" formatCode="dd/mm/yy"/>
    <numFmt numFmtId="169" formatCode="yyyy-mm-dd hh:mm:ss"/>
    <numFmt numFmtId="170" formatCode="hh:mm"/>
    <numFmt numFmtId="171" formatCode="hh:mm:ss"/>
    <numFmt numFmtId="172" formatCode="[mm]:ss"/>
  </numFmts>
  ...
  ...
  ...

14. Pomocné funkce pro konverzi časových údajů

Pro snadnější práci s časovými údaji je dostupných několik funkcí provádějících konverzi mezi několika formáty času (a data):

# Funkce Stručný popis
1 TimeFromExcelTime konverze času z Excelovského formátu (číslo s plovoucí čárkou) na hodnotu typu time.Time
2 TimeToExcelTime provádí opačnou konverzi než první funkce
3 TimeToUTCTime konverze ze standardní reprezentace času do UTC
Poznámka: aby situace nebyla tak jednoduchá, je nutné funkcím TimeFromExcelTime a TimeToExcelTime ve druhém parametru předat pravdivostní hodnotu specifikující, zda se má jako začátek „epochy“ použít rok 1900 nebo 1904. Pokud vás zajímají detaily (druhý systém byl zaveden kvůli původním Macintoshům), naleznete je například na stránce https://docs.microsoft.com/en-us/office/troubleshoot/excel/1900-and-1904-date-system.

15. Explicitně nastavené styly zobrazení

Na závěr si ukažme, jak se do sešitu uloží explicitně nastavené styly zobrazení. I následující příklad jsme již mohli vidět v předchozí části tohoto seriálu – nastavujeme v něm styl jediné buňky na listu:

package main
 
import (
        "fmt"
 
        "github.com/tealeg/xlsx/v3"
)
 
// jméno generovaného souboru
const spreadsheetName = "test10.xlsx"
 
func main() {
        // konstrukce struktury typu File
        worksheet := xlsx.NewFile()
 
        fmt.Println(worksheet)
 
        // přidání listu do sešitu
        sheet, err := worksheet.AddSheet("Tabulka1")
        if err != nil {
                panic(err)
        }
        defer sheet.Close()
 
        fmt.Println(sheet)
 
        // přidání řádku do tabulky
        row := sheet.AddRow()
 
        style := xlsx.NewStyle()
        style.Alignment.Horizontal = "right"
        style.Fill.FgColor = "FFa0FFa0"
        style.Fill.PatternType = "solid"
        style.Font.Bold = true
        style.ApplyAlignment = true
        style.ApplyFill = true
        style.ApplyFont = true
 
        // přidání buňky na řádek a naplnění hodnotou
        cell := row.AddCell()
        cell.SetString("Test")
 
        // nastavení stylu buňky
        cell.SetStyle(style)
 
        // pokus o uložení sešitu
        err = worksheet.Save(spreadsheetName)
        if err != nil {
                panic(err)
        }
}

Obsah souboru se sešitem neobsahuje žádné doplňkové informace, kromě odkazu na styl s ID=1 (zvýrazněný atribut):

<?xml version="1.0" encoding="UTF-8"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <sheetPr filterMode="false">
    <pageSetUpPr fitToPage="false"/>
  </sheetPr>
  <dimension ref="A1"/>
  <sheetViews>
    <sheetView windowProtection="false" showFormulas="false" showGridLines="true" showRowColHeaders="true" showZeros="true" rightToLeft="false" tabSelected="true" showOutlineSymbols="true" defaultGridColor="true" view="normal" topLeftCell="A1" colorId="64" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100" workbookViewId="0">
      <selection pane="topLeft" activeCell="A1" activeCellId="0" sqref="A1"/>
    </sheetView>
  </sheetViews>
  <sheetFormatPr defaultRowHeight="12.85"/>
  <sheetData>
    <row r="1">
      <c r="A1" s="1" t="s">
        <v>0</v>
      </c>
    </row>
  </sheetData>
</worksheet>

Samotný styl je umístěn samostatně:

<?xml version="1.0" encoding="UTF-8"?>
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
  <fonts count="2">
    <font>
      <sz val="11"/>
      <name val="Arial"/>
      <family val="2"/>
      <color theme="1"/>
      <scheme val="minor"/>
    </font>
    <font>
      <sz val="12"/>
      <name val="Verdana"/>
      <family val="0"/>
      <charset val="0"/>
      <b/>
    </font>
  </fonts>
  <fills count="4">
    <fill>
      <patternFill patternType="none"/>
    </fill>
    <fill>
      <patternFill patternType="gray125"/>
    </fill>
    <fill>
      <patternFill patternType="solid">
        <fgColor rgb="FFa0FFa0"/>
      </patternFill>
    </fill>
    <fill>
      <patternFill patternType="lightGray"/>
    </fill>
  </fills>
  <borders count="2">
    <border>
      <left/>
      <right/>
      <top/>
      <bottom/>
    </border>
    <border>
      <left style="none"/>
      <right style="none"/>
      <top style="none"/>
      <bottom style="none"/>
    </border>
  </borders>
  <cellStyleXfs count="1">
    <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="0" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="0">
      <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/>
    </xf>
  </cellStyleXfs>
  <cellXfs count="2">
    <xf applyAlignment="0" applyBorder="0" applyFont="0" applyFill="0" applyNumberFormat="0" applyProtection="0" borderId="0" fillId="0" fontId="0" numFmtId="0">
      <alignment horizontal="general" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/>
    </xf>
    <xf applyAlignment="1" applyBorder="0" applyFont="1" applyFill="1" applyNumberFormat="0" applyProtection="0" borderId="1" fillId="2" fontId="1" numFmtId="0">
      <alignment horizontal="right" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/>
    </xf>
  </cellXfs>
</styleSheet>

Příkladem nepřímého použití stylů je specifikace barvy výplně buňky:

    <fill>
      <patternFill patternType="solid">
        <fgColor rgb="FFa0FFa0"/>
      </patternFill>
    </fill>

Tento styl výplně je referencován zde (zvýrazněný atribut):

ict ve školství 24

    <xf applyAlignment="1" applyBorder="0" applyFont="1" applyFill="1" applyNumberFormat="0" applyProtection="0" borderId="1" fillId="2" fontId="1" numFmtId="0">
      <alignment horizontal="right" indent="0" shrinkToFit="0" textRotation="0" vertical="bottom" wrapText="0"/>
    </xf>

16. Závěrem

Při pohledu na zdrojové kódy demonstračních příkladů a současně i na interní strukturu souborů .xlsx je patrné, že samotná tvorba sešitů vlastně není příliš komplikovaná (na rozdíl od již zmíněného původního formátu .xls). Ovšem tvorba nových sešitů je pouze polovina práce (a to ta snadnější) – většinou totiž potřebujeme sešity i načítat, provádět v nich změny a ty ukládat bez toho, aby se poškodil zbylý obsah sešitu. A právě touto problematikou se budeme věnovat v navazujícím článku.

17. 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 nového 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ě stovku kilobajtů), 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 spreadsheet01.go příklad, který se pokusí vytvořit prázdný sešit ve formátu Office Open XML Workbook https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet01.go
2 spreadsheet02.go sešit s jedním prázdným listem https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet02.go
3 spreadsheet03.go sešit se třemi prázdnými listy https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet03.go
4 spreadsheet04.go přidání řádků a buněk do sešitu https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet04.go
5 spreadsheet05.go zjednodušené přidání buňky na řádek s naplněním hodnotou https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet05.go
6 spreadsheet06.go ukázka podporovaných formátů buněk https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet06.go
7 spreadsheet07.go podrobnější specifikace formátu zobrazení numerických hodnot https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet07.go
8 spreadsheet08.go přidání vzorců do sešitu https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet08.go
9 spreadsheet09.go buňky obsahující hypertextové odkazy https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet09.go
10 spreadsheet10.go základ práce se styly https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet10.go
11 spreadsheet11.go sdílení stylů mezi buňkami https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet11.go
12 spreadsheet12.go různé formáty časového razítka https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet12.go
13 spreadsheet13.go sešit s jediným listem, který obsahuje buňku s celočíselnou hodnotou https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet13.go
14 spreadsheet14.go sešit s jediným listem, který obsahuje dvě buňky s pravdivostní hodnotou a hodnotou 1/3 https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet14.go
15 spreadsheet15.go sešit obsahující horizontálně spojené buňky https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet15.go
16 spreadsheet16.go sešit obsahující horizontálně spojené buňky, ovšem se špatným formátem https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet16.go
17 spreadsheet17.go sešit obsahující vertikálně spojené buňky https://github.com/tisnik/go-root/blob/master/article67/spre­adsheet17.go

18. Odkazy na Internetu

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

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.