Struktury v Golangu

V jazyce Go jsou struktury klíčovým prvkem pro vytváření vlastních datových typů. Umožňují seskupovat různé datové položky do jednoho celku, což je velmi praktické při programování.

V tomto článku se podíváme na základy struktur a ukážeme si jejich využití na několika příkladech v Go programech.

Pojďme na to!

Co jsou struktury?

Struktura je kolekce datových polí, která mohou mít různé datové typy. Tyto pole jsou sdružena pod jedním názvem. Struktury slouží ke sdružování dat do smysluplných celků, takzvaných záznamů. Mohou obsahovat jak standardní datové typy, tak i další, uživatelsky definované typy (včetně dalších struktur).

Struktury v Go jsou proměnlivé, což znamená, že jejich obsah lze měnit během běhu programu.

Použití struktur zlepšuje čitelnost a organizaci kódu. Umožňují nám vytvářet a předávat komplexní datové struktury mezi různými částmi programu. Představte si například, že byste museli předávat deset parametrů do funkce. Použitím struktury můžete všechny tyto parametry sdružit do jedné proměnné a předat tak funkci pouze jednu strukturu, což je mnohem přehlednější.

Struktury se definují pomocí klíčových slov type a struct. Pole struktury jsou uzavřena ve složených závorkách, podobně jako je tomu u tříd v Javě. Každé pole má svůj název a datový typ. Podrobněji si to rozebereme v následující části.

Pokud máte zkušenosti s objektově orientovaným programováním (OOP), můžete si strukturu představit jako třídu, ale bez podpory dědičnosti.

Jak deklarovat struktury

Nyní, když víme, co to struktury jsou a proč se používají, je čas naučit se je deklarovat. Základní syntaxe vypadá takto:

type nazev_struktury struct {
     pole1 typ_pole1
     pole2 typ_pole2
  }

Klíčová slova `type` a `struct` jsou povinná, a struktura obsahuje sadu polí s jejich specifickými datovými typy.

Pojďme si to ukázat na příkladu:

package main

import (
  "fmt"
)

type Uzivatel struct {
  jmeno       string
  vek         int
  stavUctu    float32
}

func main() {
  var uzivatel Uzivatel
  fmt.Println(uzivatel)
}

V tomto příkladu definujeme strukturu `Uzivatel`, která obsahuje pole pro jméno (řetězec), věk (celé číslo) a stav účtu (desetinné číslo). V hlavní funkci deklarujeme proměnnou `uzivatel` typu `Uzivatel` a vypíšeme ji. Výsledkem je vypsání nulových hodnot pro jednotlivá pole, protože struktura ještě nebyla inicializována. Nulová hodnota je implicitní počáteční hodnota každého datového typu.

{ 0 0}

Inicializace struktur

V předchozí části jsme viděli, jak struktury deklarovat. Nyní si ukážeme, jak jim přiřadit konkrétní hodnoty. Podívejte se na následující příklad:

package main

import (
  "fmt"
)

type Uzivatel struct {
  jmeno       string
  vek         int
  stavUctu    float32
}

func main() {
  // Inicializace s názvy polí
  uzivatel1 := Uzivatel{
    jmeno:       "Karel",
    vek:         24,
    stavUctu:    100.0,
  }

  // Inicializace bez názvů polí
  uzivatel2 := Uzivatel{"Jana", 21, 1000.0}

  fmt.Println(uzivatel1)
  fmt.Println(uzivatel2)
}

Kód demonstruje, jak inicializovat struktury se specifikací názvů polí i bez nich. Výsledkem tohoto kódu bude:

{Karel 24 100}
 {Jana 21 1000}

Pokud při inicializaci vynecháme některé pole, bude mít toto pole implicitně nulovou hodnotu.

uzivatel1 := Uzivatel{
  jmeno:    "Karel",
  vek:      24,
}

// Výstup - {Karel 24 0.0}

Struktury můžeme vytvářet i pomocí klíčového slova `new`. Jak na to, si ukážeme v následující části.

Přístup k polím struktury

Už umíme struktury vytvářet i inicializovat. Podívejme se nyní, jak k jejich polím přistupovat. K tomu v Go slouží operátor tečka. Navážeme na předchozí příklad a ukážeme si, jak se dostat k poli `jmeno` a `vek`.

package main

import (
  "fmt"
)

type Uzivatel struct {
  jmeno       string
  vek         int
  stavUctu    float32
}

func main() {
  // Inicializace s názvy polí
  uzivatel := Uzivatel{
    jmeno:       "Karel",
    vek:         24,
    stavUctu:    100.0,
  }

  fmt.Println(uzivatel.jmeno)
  fmt.Println(uzivatel.vek)
  fmt.Println(uzivatel.stavUctu)
}

Pole struktury se zpřístupňují pomocí zápisu `nazev_struktury.nazev_pole`. Výstup tohoto kódu bude:

Karel
 24
 100

Jak už jsme zmínili, struktury můžeme vytvářet i pomocí klíčového slova `new`. Podívejme se na to:

uzivatel := new(Uzivatel)
uzivatel.jmeno = "Karel"
uzivatel.vek = 24
uzivatel.stavUctu = 100.0

fmt.Println(uzivatel)

// Výstup - &{Karel 24 100}

Klíčové slovo `new` vrací ukazatel na inicializovanou strukturu. V Go není nutné ukazatel explicitně dereferencovat, takže `fmt.Println(*uzivatel)` by vedlo ke stejnému výstupu.

Vnořené struktury

Struktury v Go mohou obsahovat i další, uživatelsky definované typy, včetně dalších struktur. Tímto způsobem můžeme vytvářet vnořené struktury.

package main

import (
  "fmt"
)

type Uzivatel struct {
  jmeno       string
  vek         int
  stavUctu    float32
  roleDetails RoleDetails
}

type RoleDetails struct {
  pozice string
  tym      string
}

func main() {
  roleDetailProKarla := RoleDetails{
    pozice: "Software Engineer",
    tym:     "Transport",
  }
  uzivatel := Uzivatel{
    jmeno:       "Karel",
    vek:         24,
    stavUctu:    100.0,
    roleDetails: roleDetailProKarla,
  }

  fmt.Println(uzivatel)
}

V tomto příkladu je struktura `RoleDetails` součástí struktury `Uzivatel`. Výstup bude vypadat takto:

{Karel 24 100 {Software Engineer Transport}}

Pro přístup k vnořeným polím použijeme operátor tečka:

`uzivatel.roleDetails.pozice`

Rovnost struktur

Dvě struktury jsou si rovny, pokud se rovnají všechny jejich pole, a to jak vestavěné, tak uživatelsky definované typy. Ne všechny datové typy lze však porovnávat (například mapy nejsou přímo porovnatelné). Ukážeme si to na příkladu:

package main

import (
  "fmt"
)

type Uzivatel struct {
  jmeno       string
  vek         int
  stavUctu    float32
}

func main() {
  uzivatel1 := Uzivatel{
    jmeno:       "Karel",
    vek:         24,
    stavUctu:    100.0,
  }
  uzivatel2 := Uzivatel{
    jmeno:       "Karel",
    vek:         24,
    stavUctu:    100.0,
  }
  uzivatel3 := Uzivatel{
    jmeno:       "Jana",
    vek:         21,
    stavUctu:    1000.0,
  }

  if uzivatel1 == uzivatel2 {
    fmt.Println("uzivatel1 a uzivatel2 jsou si rovny")
  } else {
    fmt.Println("uzivatel1 a uzivatel2 si nejsou rovny")
  }

  if uzivatel1 == uzivatel3 {
    fmt.Println("uzivatel1 a uzivatel3 jsou si rovny")
  } else {
    fmt.Println("uzivatel1 a uzivatel3 si nejsou rovny")
  }
}

Prázdné a nulové struktury jsou si rovny. Na pořadí polí nezáleží, důležité je, aby se hodnoty na odpovídajících místech shodovaly. Výstup z tohoto kódu bude:

uzivatel1 a uzivatel2 jsou si rovny
uzivatel1 a uzivatel3 si nejsou rovny

Závěr

Skvělé!

Nyní jste připraveni používat struktury v jazyce Go. Prošli jsme základy jako deklaraci, inicializaci a přístup k polím struktury. Také jsme si ukázali, jak porovnat dvě struktury, a implementovali jsme vnořenou strukturu. Zde je několik zdrojů, kde se o strukturách můžete dozvědět více:

O strukturách se dá dozvědět mnohem více, ale pro začátek je to dobrý základ. Doufám, že jste se naučili něco nového!

Pokračujte v prozkoumávání a učení se!