Sök…


Introduktion

Strukturer är uppsättningar av olika variabler packade ihop. Strukturen i sig är bara ett paket som innehåller variabler och gör dem lättillgängliga.

Till skillnad från i C kan Go's strukturer ha metoder kopplade till dem. Det gör att de också kan implementera gränssnitt. Det gör Gos strukturer som liknar objekt, men de saknar (förmodligen avsiktligt) några viktiga funktioner kända på objektorienterade språk som arv.

Grunddeklaration

En grundstruktur förklaras enligt följande:

type User struct {
    FirstName, LastName string
    Email               string
    Age                 int
}

Varje värde kallas ett fält. Fält skrivs vanligtvis en per rad, med fältets namn före dess typ. Påföljande fält av samma typ kan kombineras som FirstName och LastName i exemplet ovan.

Exporterade kontra oexporterade fält (privat vs offentligt)

Strukturfält vars namn börjar med en stor bokstav exporteras. Alla andra namn exporteras inte.

type Account struct {
    UserID      int    // exported
    accessToken string // unexported
}

Oporterade fält kan endast nås med kod inom samma paket. Som sådan, om du någonsin kommer åt ett fält från ett annat paket, måste namnet börja med en stor bokstav.

package main

import "bank"

func main() {
    var x = &bank.Account{
        UserID: 1,          // this works fine
        accessToken: "one", // this does not work, since accessToken is unexported
    }
}

Men inifrån bank kan du komma åt både användarnamn och accessToken utan problem.

Paketet bank skulle kunna genomföras så här:

package bank

type Account struct {
    UserID int
    accessToken string
}

func ProcessUser(u *Account) {    
    u.accessToken = doSomething(u) // ProcessUser() can access u.accessToken because 
                                   // it's defined in the same package
}

Sammansättning och inbäddning

Sammansättning ger ett alternativ till arv. En struktur kan innehålla en annan typ efter namn i sin förklaring:

type Request struct {
    Resource string
}

type AuthenticatedRequest struct {
    Request
    Username, Password string
}

I exemplet ovan kommer AuthenticatedRequest att innehålla fyra offentliga medlemmar: Resource , Request , Username och Password .

Sammansatta strukturer kan instanseras och användas på samma sätt som vanliga strukturer:

func main() {
    ar := new(AuthenticatedRequest)
    ar.Resource = "example.com/request"
    ar.Username = "bob"
    ar.Password = "P@ssw0rd"
    fmt.Printf("%#v", ar)
}

spela det på lekplatsen

inbäddning

I föregående exempel är Request ett inbäddat fält. Sammansättningen kan också uppnås genom inbäddning av en annan typ. Detta är till exempel användbart för att dekorera en struktur med mer funktionalitet. Fortsätt till exempel med resursexemplet, vi vill ha en funktion som formaterar innehållet i resursfältet för att prefixera det med http:// eller https:// . Vi har två alternativ: skapa de nya metoderna på AuthenticatedRequest eller bädda in dem från en annan struktur:

type ResourceFormatter struct {}

func(r *ResourceFormatter) FormatHTTP(resource string) string {
    return fmt.Sprintf("http://%s", resource)
}
func(r *ResourceFormatter) FormatHTTPS(resource string) string {
    return fmt.Sprintf("https://%s", resource)
}


type AuthenticatedRequest struct {
    Request
    Username, Password string
    ResourceFormatter
}

Och nu kan huvudfunktionen göra följande:

func main() {
    ar := new(AuthenticatedRequest)
    ar.Resource = "www.example.com/request"
    ar.Username = "bob"
    ar.Password = "P@ssw0rd"

    println(ar.FormatHTTP(ar.Resource))
    println(ar.FormatHTTPS(ar.Resource))

    fmt.Printf("%#v", ar)
}

Se att AuthenticatedRequest som har en ResourceFormatter inbäddad struktur.

Men nackdelen med det är att du inte kan komma åt objekt utanför din komposition. Så ResourceFormatter kan inte komma åt medlemmar från AuthenticatedRequest .

spela det på lekplatsen

metoder

Strukturmetoder liknar funktioner:

type User struct {
    name string
}

func (u User) Name() string {
    return u.name
}

func (u *User) SetName(newName string) {
    u.name = newName
}

Den enda skillnaden är tillägget av metodmottagaren. Det kan förklaras antingen som en instans av typen eller en pekare till en instans av typen. Eftersom SetName() muterar instansen måste mottagaren vara en pekare för att genomföra en permanent ändring av förekomsten.

Till exempel:

package main

import "fmt"

type User struct {
    name string
}

func (u User) Name() string {
    return u.name
}

func (u *User) SetName(newName string) {
    u.name = newName
}

func main() {
    var me User

    me.SetName("Slim Shady")
    fmt.Println("My name is", me.Name())
}

Gå lekplats

Anonym struktur

Det är möjligt att skapa en anonym struktur:

data := struct {
    Number int 
    Text   string
} { 
    42, 
    "Hello world!",
}

Fullständigt exempel:

package main

import (
    "fmt"
)

func main() {
    data := struct {Number int; Text string}{42, "Hello world!"} // anonymous struct
    fmt.Printf("%+v\n", data)
}

spela det på lekplatsen

Tags

Strukturfält kan ha taggar associerade med dem. Dessa taggar kan läsas av reflect för att få anpassad information angiven om ett fält av utvecklaren.

struct Account {
    Username      string `json:"username"`
    DisplayName   string `json:"display_name"`
    FavoriteColor string `json:"favorite_color,omitempty"`
}

I exemplet ovan används taggarna för att ändra nyckelnamnen som används av encoding/json paketet när man marsjalerar eller avmarkerar JSON.

Medan taggen kan vara vilket strängvärde som helst, anses det vara bästa praxis att använda mellanseparerad key:"value" -par:

struct StructName {
    FieldName int `package1:"customdata,moredata" package2:"info"`
}

Strukturtaggarna som används med encoding/xml och encoding/json paketet används i hela biblioteket.

Skapa strukturkopior.

En struktur kan helt enkelt kopieras med uppdrag.

type T struct {
    I int
    S string
}

// initialize a struct
t := T{1, "one"}

// make struct copy
u := t // u has its field values equal to t

if u == t { // true
    fmt.Println("u and t are equal") // Prints: "u and t are equal"
}

I ovanstående fall är 't' och 'u' nu separata objekt (strukturvärden).

Eftersom T inte innehåller några referenstyper (skivor, karta, kanaler) som dess fält, kan t och u ovan ändras utan att påverka varandra.

fmt.Printf("t.I = %d, u.I = %d\n", t.I, u.I) // t.I = 100, u.I = 1

Om T innehåller en referenstyp, till exempel:

type T struct {
    I  int
    S  string
    xs []int // a slice is a reference type
}

Sedan kopierar en enkel kopia efter tilldelning även värdet på skivtypfältet till det nya objektet. Detta skulle resultera i två olika objekt som hänvisar till samma skivaobjekt.

// initialize a struct
t := T{I: 1, S: "one", xs: []int{1, 2, 3}}

// make struct copy
u := t // u has its field values equal to t

Eftersom både u och t hänvisar till samma skiva genom deras fält xs som uppdaterar ett värde i segmentet för ett objekt skulle återspegla förändringen i det andra.

// update a slice field in u
u.xs[1] = 500

fmt.Printf("t.xs = %d, u.xs = %d\n", t.xs, u.xs)
// t.xs = [1 500 3], u.xs = [1 500 3]

Därför måste extra försiktighet vidtas för att se till att denna egenskap av referenstyp inte ger oavsiktligt beteende.

För att exempelvis kopiera objekt ovan, kan en explicerad kopia av skivfältet utföras:

// explicitly initialize u's slice field
u.xs = make([]int, len(t.xs))
// copy the slice values over from t
copy(u.xs, t.xs)

// updating slice value in u will not affect t
u.xs[1] = 500

fmt.Printf("t.xs = %d, u.xs = %d\n", t.xs, u.xs)
// t.xs = [1 2 3], u.xs = [1 500 3]

Strukturbokstäver

Ett värde av en strukturtyp kan skrivas med en strukturell bokstav som anger värden för dess fält.

type Point struct { X, Y int }
p := Point{1, 2}

Exemplet ovan specificerar alla fält i rätt ordning. Vilket är inte användbart eftersom programmerare måste komma ihåg exakta fält i ordning. Oftare kan en struktur initialiseras genom att lista några eller alla fältnamn och deras motsvarande värden.

anim := gif.GIF{LoopCount: nframes}

Utelämnade fält är inställda på nollvärdet för dess typ.

Obs: De två formerna kan inte blandas i samma bokstav.

Tom struktur

En struktur är en sekvens av namngivna element, kallade fält, som alla har ett namn och en typ. Tom struct har inga fält, som den anonyma tomma strukturen:

var s struct{}

Eller som den här namnet tomma strukturen:

type T struct{}

Det intressanta med den tomma strukturen är att storleken är noll (prova Go Playground ):

fmt.Println(unsafe.Sizeof(s))

Detta skriver ut 0 , så den tomma strukturen i sig tar inget minne. så det är ett bra alternativ för att avsluta kanalen, som (prova The Go Playground ):

package main

import (
    "fmt"
    "time"
)

func main() {
    done := make(chan struct{})
    go func() {
        time.Sleep(1 * time.Second)
        close(done)
    }()

    fmt.Println("Wait...")
    <-done
    fmt.Println("done.")
}



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow