Övning – Använda structs

Slutförd

Det finns tillfällen då du behöver representera en samling fält i en struktur. När du till exempel behöver skriva ett löneprogram måste du använda en datastruktur för anställda. I Go kan du använda structs för att gruppera olika fält som kan bilda en post.

En struct i Go är en annan datatyp som kan innehålla noll eller fler fält av godtyckliga typer och representera dem som en enda entitet.

I det här avsnittet utforskar vi varför structs är viktiga och hur du använder dem.

Deklarera och initiera en struct

Om du vill deklarera en struct måste du använda nyckelordet struct , tillsammans med listan över fält och deras typer som du vill att den nya datatypen ska ha. Om du till exempel vill definiera en anställds struct kan du använda följande kod:

type Employee struct {
    ID        int
    FirstName string
    LastName  string
    Address   string
}

Sedan kan du deklarera en variabel med den nya typen som du vanligtvis gör med andra typer, så här:

var john Employee

Och om du vill deklarera och initiera en variabel samtidigt kan du göra det på följande sätt:

employee := Employee{1001, "John", "Doe", "Doe's Street"}

Observera att du måste ange ett värde för vart och ett av fälten från structen. Men det kan vara problematiskt ibland. Du kan också vara mer specifik om de fält som du vill initiera i en struct:

employee := Employee{LastName: "Doe", FirstName: "John"}

Observera att från föregående instruktion spelar det ingen roll vilken ordning du tilldelar värden till varje fält. Dessutom spelar det ingen roll om du inte anger något värde för något annat fält. Go tilldelar ett standardvärde beroende på fältdatatypen.

Om du vill komma åt enskilda fält i en struct kan du göra det med hjälp av punkt notationen (.), som i det här exemplet:

employee.ID = 1001
fmt.Println(employee.FirstName)

Slutligen kan du använda operatorn & för att ge en pekare till structen, som följande kod visar:

package main

import "fmt"

type Employee struct {
    ID        int
    FirstName string
    LastName  string
    Address   string
}

func main() {
    employee := Employee{LastName: "Doe", FirstName: "John"}
    fmt.Println(employee)
    employeeCopy := &employee
    employeeCopy.FirstName = "David"
    fmt.Println(employee)
}

När du kör föregående kod visas följande utdata:

{0 John Doe }
{0 David Doe }

Observera hur structen blir föränderlig när du använder pekare.

Struct-inbäddning

Med Structs i Go kan du bädda in en annan struct i en struct. Det kommer att finnas tillfällen då du vill minska upprepningen och återanvända en gemensam struct. Anta till exempel att du vill omstrukturera den tidigare koden så att den har en datatyp för en anställd och en annan för en entreprenör. Du kan ha en Person struct som innehåller vanliga fält, som det här exemplet:

type Person struct {
    ID        int
    FirstName string
    LastName  string
    Address   string
}

Du kan sedan deklarera andra typer som bäddar in en Person typ, till exempel en Employee och en Contractor. Om du vill bädda in en annan struct skapar du ett nytt fält, som det här exemplet:

type Employee struct {
    Information Person
    ManagerID   int
}

Men för att referera till ett fält från structen Person måste du inkludera Information fältet från en variabel för anställda, som i det här exemplet:

var employee Employee
employee.Information.FirstName = "John"

Om du omstrukturerar kod som vi gör skulle det bryta vår kod. Du kan också inkludera ett nytt fält med samma namn som den struct som du bäddar in, som i det här exemplet:

type Employee struct {
    Person
    ManagerID int
}

Som en demonstration kan du använda följande kod:

package main

import "fmt"

type Person struct {
    ID        int
    FirstName string
    LastName  string
    Address   string
}

type Employee struct {
    Person
    ManagerID int
}

type Contractor struct {
    Person
    CompanyID int
}

func main() {
    employee := Employee{
        Person: Person{
            FirstName: "John",
        },
    }
    employee.LastName = "Doe"
    fmt.Println(employee.FirstName)
}

Observera hur du kommer åt fältet FirstName från en Employee struct utan att behöva ange Person fältet eftersom det bäddar in alla fält automatiskt. Men när du initierar en struct måste du vara specifik om vilket fält du vill tilldela ett värde till.

Koda och avkoda structs med JSON

Slutligen kan du använda structs för att koda och avkoda data i JSON. Go har utmärkt stöd för JSON-formatet, och det ingår redan i standardbibliotekspaketen.

Du kan också göra saker som att byta namn på namnet på ett fält från structen. Anta till exempel att du inte vill att JSON-utdata ska visas FirstName utan helt enkelt name eller ignorera tomma fält. Du kan använda fälttaggar som det här exemplet visar:

type Person struct {
    ID        int    
    FirstName string `json:"name"`
    LastName  string
    Address   string `json:"address,omitempty"`
}

Om du sedan vill koda en struct till JSON använder json.Marshal du funktionen. Och om du vill avkoda en JSON-sträng till en datastruktur använder json.Unmarshal du funktionen. Här är ett exempel som sätter ihop allt, kodar en matris med anställda till JSON och avkodar utdata till en ny variabel:

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    ID        int
    FirstName string `json:"name"`
    LastName  string
    Address   string `json:"address,omitempty"`
}

type Employee struct {
    Person
    ManagerID int
}

type Contractor struct {
    Person
    CompanyID int
}

func main() {
    employees := []Employee{
        Employee{
            Person: Person{
                LastName: "Doe", FirstName: "John",
            },
        },
        Employee{
            Person: Person{
                LastName: "Campbell", FirstName: "David",
            },
        },
    }

    data, _ := json.Marshal(employees)
    fmt.Printf("%s\n", data)

    var decoded []Employee
    json.Unmarshal(data, &decoded)
    fmt.Printf("%v", decoded)
}

När du kör föregående kod visas följande utdata:

[{"ID":0,"name":"John","LastName":"Doe","ManagerID":0},{"ID":0,"name":"David","LastName":"Campbell","ManagerID":0}]
[{{0 John Doe } 0} {{0 David Campbell } 0}]