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

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

results matching ""

    No results matching ""