Exercício - Use structs
Há momentos em que você precisa representar uma coleção de campos em uma estrutura. Por exemplo, quando você precisa escrever um programa de folha de pagamento, você precisa usar uma estrutura de dados de funcionários. Em Go, você pode usar structs para agrupar diferentes campos que podem formar um registro.
Um struct em Go é outro tipo de dados que pode conter zero ou mais campos de tipos arbitrários e representá-los como uma única entidade.
Nesta seção, vamos explorar por que as estruturas são essenciais e como usá-las.
Declarar e inicializar uma struct
Para declarar uma estrutura, você precisa usar a palavra-chave struct
, juntamente com a lista de campos e seus tipos que você deseja que seu novo tipo de dados tenha. Por exemplo, para definir uma estrutura de funcionário, você pode usar o seguinte código:
type Employee struct {
ID int
FirstName string
LastName string
Address string
}
Em seguida, você pode declarar uma variável com o novo tipo como normalmente faria com outros tipos, como este:
var john Employee
E se você quiser declarar e inicializar uma variável ao mesmo tempo, você pode fazê-lo desta maneira:
employee := Employee{1001, "John", "Doe", "Doe's Street"}
Observe que você precisa especificar um valor para cada um dos campos da struct. Mas isso pode ser problemático às vezes. Como alternativa, você pode ser mais específico sobre os campos que deseja inicializar em uma estrutura:
employee := Employee{LastName: "Doe", FirstName: "John"}
Observe que, a partir da instrução anterior, a ordem em que você atribui valores a cada campo não importa. Além disso, não importa se você não especificar um valor para nenhum outro campo. Go atribuirá um valor padrão dependendo do tipo de dados do campo.
Para acessar campos individuais de uma estrutura, você pode fazê-lo usando a notação de ponto (.
), como este exemplo:
employee.ID = 1001
fmt.Println(employee.FirstName)
Por fim, você pode usar o &
operador para produzir um ponteiro para o struct, como o código a seguir demonstra:
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)
}
Quando você executa o código anterior, você vê a seguinte saída:
{0 John Doe }
{0 David Doe }
Observe como a estrutura se torna mutável quando você usa ponteiros.
Incorporação de estruturas
Structs in Go permitem que você incorpore outro struct dentro de um struct. Haverá momentos em que você vai querer reduzir a repetição e reutilizar uma estrutura comum. Por exemplo, digamos que você queira refatorar o código anterior para ter um tipo de dados para um Funcionário e outro para um Contratante. Você pode ter uma Person
struct que contém campos comuns, como este exemplo:
type Person struct {
ID int
FirstName string
LastName string
Address string
}
Em seguida, você pode declarar outros tipos que incorporam um Person
tipo, como um Employee
e um Contractor
. Para incorporar outra estrutura, crie um novo campo, como este exemplo:
type Employee struct {
Information Person
ManagerID int
}
Mas para fazer referência a um campo da Person
struct, você precisará incluir o Information
campo de uma variável de funcionário, como este exemplo:
var employee Employee
employee.Information.FirstName = "John"
Se você estiver refatorando o código como estamos fazendo, isso quebraria nosso código. Como alternativa, você pode incluir um novo campo com o mesmo nome da estrutura que está incorporando, como este exemplo:
type Employee struct {
Person
ManagerID int
}
Como demonstração, você pode usar o seguinte código:
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)
}
Observe como você acessa o FirstName
campo a partir de uma Employee
struct sem precisar especificar o Person
campo porque ele está incorporando todos os seus campos automaticamente. Mas, quando você está inicializando uma estrutura, você precisa ser específico sobre qual campo você deseja atribuir um valor.
Codifique e decodifice estruturas com JSON
Finalmente, você pode usar structs para codificar e decodificar dados em JSON. Go tem excelente suporte para o formato JSON, e já está incluído nos pacotes de biblioteca padrão.
Você também pode fazer coisas como renomear o nome de um campo da estrutura. Por exemplo, digamos que você não queira que a saída JSON seja exibida FirstName
, mas simplesmente name
ignore campos vazios. Você pode usar tags de campo como este exemplo mostra:
type Person struct {
ID int
FirstName string `json:"name"`
LastName string
Address string `json:"address,omitempty"`
}
Em seguida, para codificar uma struct em JSON, use a json.Marshal
função. E para decodificar uma cadeia de caracteres JSON em uma estrutura de dados, use a json.Unmarshal
função. Aqui está um exemplo que junta tudo, codificando uma matriz de funcionários para JSON e decodificando a saída em uma nova variável:
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)
}
Quando você executa o código anterior, você vê a seguinte saída:
[{"ID":0,"name":"John","LastName":"Doe","ManagerID":0},{"ID":0,"name":"David","LastName":"Campbell","ManagerID":0}]
[{{0 John Doe } 0} {{0 David Campbell } 0}]