Files
2017-01-11 11:08:11 -02:00

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)
}
![](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)