215 lines
6.5 KiB
Markdown
215 lines
6.5 KiB
Markdown
# 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)
|
|
}
|
|
|
|

|
|
|
|
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)
|