# 2.4 struct ## struct Podemos definir novos tipos de contêineres de outras propriedades ou campos em Go exatamente como em outras linguagens de programação. Por exemplo, podemos criar um tipo chamado `person` com os campos name (nome) e age (idade) para representar uma pessoa. Chamamos este tipo de `struct` (estrutura). type person struct { name string age int } Veja como é fácil definir uma `struct`! Existem dois campos. - `name` é uma `string` usada para armazenar o nome da pessoa. - `age` é um `int` usado para armazenar a idade da pessoa. Vamos ver como utilizar isto. type person struct { name string age int } var P person // p é do tipo person P.name = "Astaxie" // atribui "Astaxie" para o campo 'name' de p P.age = 25 // atribui 25 para o campo 'age' de p fmt.Printf("The person's name is %s\n", P.name) // acessa o campo 'name' de p Existem outras três maneiras de definir uma estrutura. - Atribuir os valores iniciais em ordem P := person{"Tom", 25} - Usar o formato `field:value` (campo:valor) para inicializar a estrutura sem ordem P := person{age:24, name:"Bob"} - Definir uma estrutura anônima e então inicializar ela P := struct{name string; age int}{"Amy",18} Vejamos um exemplo completo. package main import "fmt" // define um novo tipo type person struct { name string age int } // compara a idade de duas pessoas e retorna dois valores: a pessoa mais velha e a diferença de idade // estrutura é passada por valor func Older(p1, p2 person) (person, int) { if p1.age>p2.age { return p1, p1.age-p2.age } return p2, p2.age-p1.age } func main() { var tom person // inicialização tom.name, tom.age = "Tom", 18 // inicializa dois valores pelo formato "campo:valor" bob := person{age:25, name:"Bob"} // inicializa dois valores em ordem paul := person{"Paul", 43} tb_Older, tb_diff := Older(tom, bob) tp_Older, tp_diff := Older(tom, paul) bp_Older, bp_diff := Older(bob, paul) fmt.Printf("Of %s and %s, %s is older by %d years\n", tom.name, bob.name, tb_Older.name, tb_diff) fmt.Printf("Of %s and %s, %s is older by %d years\n", tom.name, paul.name, tp_Older.name, tp_diff) fmt.Printf("Of %s and %s, %s is older by %d years\n", bob.name, paul.name, bp_Older.name, bp_diff) } ### Campos incorporados em struct Acabei de apresentar a você como definir uma estrutura com nomes de campos e tipos. Na verdade, Go suporta campos sem nomes, mas com tipos. Chamamos esses campos de campos incorporados (embedded fields). Quando um campo incorporado é uma estrutura, todos os campos desta estrutura serão implicitamente campos da estrutura onde ela foi incorporada. Vejamos um exemplo. package main import "fmt" type Human struct { name string age int weight int } type Student struct { Human // campo incorporado, significa que a estrutura Student inclui todos os campos que Human possui specialty string } func main() { // inicializa um estudante mark := Student{Human{"Mark", 25, 120}, "Computer Science"} // acessa os campos fmt.Println("His name is ", mark.name) fmt.Println("His age is ", mark.age) fmt.Println("His weight is ", mark.weight) fmt.Println("His specialty is ", mark.specialty) // modifica a especialidade mark.specialty = "AI" fmt.Println("Mark changed his specialty") fmt.Println("His specialty is ", mark.specialty) // modifica a idade fmt.Println("Mark become old") mark.age = 46 fmt.Println("His age is", mark.age) // modifica o peso fmt.Println("Mark is not an athlet anymore") mark.weight += 60 fmt.Println("His weight is", mark.weight) } ![](images/2.4.student_struct.png?raw=true) Figure 2.7 Herança em Student e Human Vimos que podemos acessar os campos idade e nome de Student exatamente como podemos em Human. É assim que os campos incorporados funcionam. É muito legal, não é? Espere, tem algo mais legal! Você pode até usar o Student para acessar o Human neste campo incorporado! mark.Human = Human{"Marcus", 55, 220} mark.Human.age -= 1 Todos os tipos em Go podem ser usados como campos incorporados. package main import "fmt" type Skills []string type Human struct { name string age int weight int } type Student struct { Human // estrutura como campo incorporado Skills // string slice como campo incorporado int // tipo embutido como campo incorporado specialty string } func main() { // inicializa o Student Jane jane := Student{Human:Human{"Jane", 35, 100}, specialty:"Biology"} // acessa os campos fmt.Println("Her name is ", jane.name) fmt.Println("Her age is ", jane.age) fmt.Println("Her weight is ", jane.weight) fmt.Println("Her specialty is ", jane.specialty) // modifica o valor do campo skill jane.Skills = []string{"anatomy"} fmt.Println("Her skills are ", jane.Skills) fmt.Println("She acquired two new ones ") jane.Skills = append(jane.Skills, "physics", "golang") fmt.Println("Her skills now are ", jane.Skills) // modifica o campo incorporado jane.int = 3 fmt.Println("Her preferred number is", jane.int) } No exemplo acima, podemos ver que todos os tipos podem ser campos incorporados e podemos usar funções para operar sobre eles. No entanto, existe mais um problema. Se Human possui um campo chamado `phone` e Student possui um campo com o mesmo nome, o que devemos fazer? Go usa uma maneira muito simples para resolver isto. Os campos externos obtêm níveis de acesso superiores, o que significa que quando você acessa `student.phone`, você irá obter o campo chamado phone de Student, e não aquele definido na estrutura Human. Este recurso pode ser visto simplesmente como uma sobrecarga de campo (field `overload`ing). package main import "fmt" type Human struct { name string age int phone string // Human possui o campo phone } type Employee struct { Human // campo incorporado Human specialty string phone string // phone em Employee } func main() { Bob := Employee{Human{"Bob", 34, "777-444-XXXX"}, "Designer", "333-222"} fmt.Println("Bob's work phone is:", Bob.phone) // acessa o campo phone em Human fmt.Println("Bob's personal phone is:", Bob.Human.phone) } ## Links - [Sumário](preface.md) - Seção anterior: [Declarações de controle e funções](02.3.md) - Próxima seção: [Orientado a Objeto](02.5.md)