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
é umastring
usada para armazenar o nome da pessoa.age
é umint
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 ordemP := 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
- Seção anterior: Declarações de controle e funções
- Próxima seção: Orientado a Objeto