Esta pagina se ve mejor con JavaScript habilitado

Go structs

 ·  🎃 kr0m

Las estructuras en Go proporcionando una forma de agrupar datos relacionados bajo un mismo tipo. A diferencia de los lenguajes orientados a objetos tradicionales, Go no tiene clases, pero las estructuras permiten una funcionalidad similar al permitir la creación de tipos complejos que pueden contener múltiples campos de diferentes tipos.

Este artículo es bastante extenso así que lo he organizado de la siguiente manera:


Si eres nuevo en el mundo de Go te recomiendo los siguientes artículos anteriores:


Estructura básica:

Imaginemos que queremos gestionar personas desde nuestro programa y los datos de las personas constan de varios datos, como el nombre, la edad y el sexo. Podríamos crearnos un map para la edad y otro para el sexo ambos utilizando el nombre como índice, pero resulta mucho mas sencillo una estructura.

En el siguiente ejemplo creamos dos objetos de tipo persona con distintos datos cada uno.

vi 00-structures.go
package main

import "fmt"

type person struct {
    name string
    age int
    sex string
}

func main() {
    person1 := person {
        name:   "John",
        age:    25,
        sex:    "Male",
    }

    person2 := person {
        name:   "Sarah",
        age:    45,
        sex:    "Female",
    }

    fmt.Println(person1)
    fmt.Println("Name: ", person1.name)
    fmt.Println("Age: ", person1.age)
    fmt.Println("Sex: ", person1.sex)

    fmt.Println(person2)
    fmt.Println("Name: ", person2.name)
    fmt.Println("Age: ", person2.age)
    fmt.Println("Sex: ", person2.sex)
}
go run 00-structures.go
{John 25 Male}
Name:  John
Age:  25
Sex:  Male
{Sarah 45 Female}
Name:  Sarah
Age:  45
Sex:  Female

Estructuras anónimas:

Cuando una estructura incorpora otra, no hace falta definir el campo como de tipo estructura2 en estructura1, este tipo de campos son llamados anónimos.

Veamos primero un ejemplo en el que si se define el tipo.

package main

import (
    "fmt"
)

func main() {
    type personalData struct {
        name string
        age  int
        sex  string
    }

    type client struct {
        person    personalData
        address   string
        telephone int
    }

    client1 := client{
        person: personalData{
            name: "John",
            age:  25,
            sex:  "Male",
        },
        address:   "Paper street",
        telephone: 666334455,
    }

    fmt.Println("client1 name: ", client1.person.name)
    fmt.Println("client1 age: ", client1.person.age)
    fmt.Println("client1 sex: ", client1.person.sex)
    fmt.Println("client1 address: ", client1.address)
    fmt.Println("client1 telephone: ", client1.telephone)
}
client1 name:  John
client1 age:  25
client1 sex:  Male
client1 address:  Paper street
client1 telephone:  666334455

La versión con campos anónimos quedaría del siguiente modo.

package main

import (
    "fmt"
)

func main() {
    type personalData struct {
        name string
        age  int
        sex  string
    }

    type client struct {
        // Anonymous field
        personalData
        address   string
        telephone int
    }

    personalDataClient1 := personalData{
        name: "John",
        age:  25,
        sex:  "Male",
    }

    client1 := client{
        // Set structure values omitting field names
        personalDataClient1,
        "Paper street",
        666334455,
    }

    // Direct personalData fields access using client1
    fmt.Println("client1 name: ", client1.name)
    fmt.Println("client1 age: ", client1.age)
    fmt.Println("client1 sex: ", client1.sex)
    fmt.Println("client1 address: ", client1.address)
    fmt.Println("client1 telephone: ", client1.telephone)
}
client1 name:  John
client1 age:  25
client1 sex:  Male
client1 address:  Paper street
client1 telephone:  666334455

Es posible incluso crear estructuras sin crear un tipo de antemano pudiendo crearlas “al vuelo” y de un solo uso.

package main

import (
    "fmt"
)

func main() {
    client1 := struct {
        name      string
        age       int
        sex       string
        address   string
        telephone int
    }{
        name:      "John",
        age:       25,
        sex:       "Male",
        address:   "Paper street",
        telephone: 666334455,
    }

    fmt.Println("client1 name: ", client1.name)
    fmt.Println("client1 age: ", client1.age)
    fmt.Println("client1 sex: ", client1.sex)
    fmt.Println("client1 address: ", client1.address)
    fmt.Println("client1 telephone: ", client1.telephone)
}
client1 name:  John
client1 age:  25
client1 sex:  Male
client1 address:  Paper street
client1 telephone:  666334455

La única limitación de los campos anónimos es que no puede tratarse de un slice.

package main

import (
    "fmt"
)

func main() {
    type client struct {
        name        string
        address   string
        telephone int
    }

    type clientList struct {
        // Anonymous slice Not allowed
        []client
    }

    client1 := client{
        name: "John",
        address: "Paper street",
        telephone: 666334455,
    }

    client2 := client{
        name: "Sarah",
        address: "Inexistent avenue",
        telephone: 555667788,
    }

    var clientSlice []client
    clientSlice = append(clientSlice, client1, client2)
    clientList1 := clientList{
        clientSlice,
    }

    for _, v := range clientList1 {
        fmt.Println(v.name)
        fmt.Println(v.address)
        fmt.Println(v.telephone)
    }
}
./test.go:15:9: syntax error: unexpected [, expected field name or embedded type

Para que funcione debemos de dejar de utilizar campos anónimos.

package main

import (
    "fmt"
)

func main() {
    type client struct {
        name      string
        address   string
        telephone int
    }

    type clientList struct {
        clients []client
    }

    client1 := client{
        name:      "John",
        address:   "Paper street",
        telephone: 666334455,
    }

    client2 := client{
        name:      "Sarah",
        address:   "Inexistent avenue",
        telephone: 555667788,
    }

    var clientSlice []client
    clientSlice = append(clientSlice, client1, client2)
    clientList1 := clientList{
        clientSlice,
    }

    for _, v := range clientList1.clients {
        fmt.Println(v.name)
        fmt.Println(v.address)
        fmt.Println(v.telephone)
    }
}
John
Paper street
666334455
Sarah
Inexistent avenue
555667788

Métodos asociados a estructuras:

Como vincular métodos a tipo ya se explicó en un artículo anterior sobre funciones , pero nunca viene mal refrescar la memoria.

En este ejemplo vincularemos un tipo de tipo estructura al método area(), en dicho método obtendremos una copia del objeto en si mismo, Go lo llama receiver en algunos lenguajes de programación lo llaman this, la forma idiomática de nombrar a dicho receiver es utilizar la primera letra del tipo del objeto.

vi 01-structures.go
package main

import "fmt"

type rectangle struct {
    Base   int
    Height int
}

func (r rectangle) area() int {
    return r.Base * r.Height
}

func main() {
    // Assign structure variable values
    rect := rectangle{Base: 3, Height: 4}
    // rect structure moreover has area method available
    // Call structure method
    area := rect.area()
    fmt.Println(area)
}
go run 01-structures.go
12

Los métodos presentan varias ventajas respecto a utilizar funciones:

  • Los métodos quedan vinculados de forma lógica a los tipos.
  • Los nombres de los métodos pueden ser reutilizados en los distintos tipos.

Composition:

En Go, el composition se refiere a la capacidad de incrustar un tipo en otro heredando sus comportamientos, extensión de funcionalidad de un tipo existente incorporando otros tipos que proporcionan funcionalidades adicionales, además de una mayor simplicidad y claridad en el diseño al permitir una estructura más modular y fácil de entender.

En este sencillo ejemplo tenemos tres estructuras:

  • person: Estructura común con un método personMethod.
  • student: Incluye un campo de tipo person, añade el string grade y tiene un método propio studentMethod.
  • teacher: Incluye un campo de tipo person, añade el int teaching_years y tiene un método propio teacherMethod.
vi 02-structures.go
package main

import "fmt"

type person struct {
    name string
    age int
    sex string
}
func (p person) personMethod() {
    fmt.Println("personMethod accessed")
}

type student struct {
    personData person
    grade string
}
func (s student) studentMethod() {
    fmt.Println("studentMethod accessed")
}

type teacher struct {
    personData person
    teachingYears int
}
func (t teacher) teacherMethod() {
    fmt.Println("teacherMethod accessed")
}

func main() {
    student := student {
        personData: person {
            name: "Ana",
            age:   20,
            sex:  "Female",
        },
        grade: "engineering",
    }
    teacher := teacher {
        personData: person {
            name: "Joe",
            age:   30,
            sex:  "Male",
        },
        teachingYears: 10,
    }

    fmt.Println(student)
    fmt.Println("Name: ", student.personData.name)
    fmt.Println("Age: ", student.personData.age)
    fmt.Println("Sex: ", student.personData.sex)
    fmt.Println("Grade: ", student.grade)
    student.personData.personMethod()
    student.studentMethod()
    fmt.Println("-----")
    fmt.Println(teacher)
    fmt.Println("Name: ", teacher.personData.name)
    fmt.Println("Age: ", teacher.personData.age)
    fmt.Println("Sex: ", teacher.personData.sex)
    fmt.Println("TeachingYears: ", teacher.teachingYears)
    teacher.personData.personMethod()
    teacher.teacherMethod()
}

Ejecutamos el código:

go run 02-structures.go

{{Ana 20 Female} engineering}
Name:  Ana
Age:  20
Sex:  Female
Grade:  engineering
personMethod accessed
studentMethod accessed
-----
{{Joe 30 Male} 10}
Name:  Joe
Age:  30
Sex:  Male
TeachingYears:  10
personMethod accessed
teacherMethod accessed

Las estructuras de Go soportan campos anónimos, esto quiere decir que podemos definir campos en las estructuras solo por el tipo, no hace falta indicar un nombre, de este modo el tipo quedará incluido. Utilizando campos anónimos al acceder a los campos de las estructuras o los métodos asociados obtendremos un código mas claro y sencillo.

El ejemplo anterior utilizando campos anónimos quedaría de la siguiente manera.

vi 03-structures.go

package main

import "fmt"

type person struct {
    name string
    age int
    sex string
}
func (p person) personMethod() {
    fmt.Println("personMethod accessed")
}

type student struct {
    person
    grade string
}
func (s student) studentMethod() {
    fmt.Println("studentMethod accessed")
}

type teacher struct {
    person
    teachingYears int
}
func (t teacher) teacherMethod() {
    fmt.Println("teacherMethod accessed")
}

func main() {
    student := student {
        person: person {
            name: "Ana",
            age:   20,
            sex:  "Female",
        },
        grade: "engineering",
    }
    teacher := teacher {
        person: person {
            name: "Joe",
            age:   30,
            sex:  "Male",
        },
        teachingYears: 10,
    }

    fmt.Println(student)
    fmt.Println("Name: ", student.name)
    fmt.Println("Age: ", student.age)
    fmt.Println("Sex: ", student.sex)
    fmt.Println("Grade: ", student.grade)
    student.personMethod()
    student.studentMethod()
    fmt.Println("-----")
    fmt.Println(teacher)
    fmt.Println("Name: ", teacher.name)
    fmt.Println("Age: ", teacher.age)
    fmt.Println("Sex: ", teacher.sex)
    fmt.Println("TeachingYears: ", teacher.teachingYears)
    teacher.personMethod()
    teacher.teacherMethod()
}

Ejecutamos el código:

go run 03-structures.go

{{Ana 20 Female} engineering}
Name:  Ana
Age:  20
Sex:  Female
Grade:  engineering
personMethod accessed
studentMethod accessed
-----
{{Joe 30 Male} 10}
Name:  Joe
Age:  30
Sex:  Male
TeachingYears:  10
personMethod accessed
teacherMethod accessed

Encapsulación de estructuras:

Hay ocasiones en las que necesitamos estar seguros de que los campos de una estructura tiene valores asignados, en el ejemplo anterior podríamos querer asegurarnos de que una persona siempre tenga un nombre o que su edad no sea negativa por ejemplo.

Una forma de asegurarse de que un objeto de un tipo cumpla con los datos requeridos es utilizar la encapsulación, esta consiste en forzar la instanciación del tipo a través de ciertos métodos.

Con el código actual podríamos instanciar una persona sin nombre:

vi 04-structures.go

package main

import "fmt"

type person struct {
    name string
    age int
    sex string
}
func (p person) personMethod() {
    fmt.Println("personMethod accessed")
}

type student struct {
    person
    grade string
}
func (s student) studentMethod() {
    fmt.Println("studentMethod accessed")
}

type teacher struct {
    person
    teachingYears int
}
func (t teacher) teacherMethod() {
    fmt.Println("teacherMethod accessed")
}

func main() {
    student := student {
        person: person {
            age:   -20,
            sex:  "Female",
        },
        grade: "engineering",
    }
    teacher := teacher {
        person: person {
            age:   -30,
            sex:  "Male",
        },
        teachingYears: 10,
    }

    fmt.Println(student)
    fmt.Println("Name: ", student.name)
    fmt.Println("Age: ", student.age)
    fmt.Println("Sex: ", student.sex)
    fmt.Println("Grade: ", student.grade)
    student.personMethod()
    student.studentMethod()
    fmt.Println("-----")
    fmt.Println(teacher)
    fmt.Println("Name: ", teacher.name)
    fmt.Println("Age: ", teacher.age)
    fmt.Println("Sex: ", teacher.sex)
    fmt.Println("TeachingYears: ", teacher.teachingYears)
    teacher.personMethod()
    teacher.teacherMethod()
}

Dando como resultado, el campo Name vacío:

go run 04-structures.go

{{ -20 Female} engineering}
Name:
Age:  -20
Sex:  Female
Grade:  engineering
personMethod accessed
studentMethod accessed
-----
{{ -30 Male} 10}
Name:
Age:  -30
Sex:  Male
TeachingYears:  10
personMethod accessed
teacherMethod accessed

Mediante encapsulación vamos a resolver dicho problema, el primer paso es hacer que las estructuras no sean accesibles de forma directa, esto se consigue moviéndolas a otro package. Cuando un tipo, variable o función se encuentra en otro package y sus nombres empiezan por minúsculas, esos tipos, variables o funciones no serán expuestos a otros packages.

La idea de la encapsulación es mover las estructuras a otro package y crear métodos que accedan a ellas, donde estos métodos si que serán exportados ya que sus nombres empezarán con mayúsculas quedando de este modo visibles desde otros packages.

Como detalle final debemos tener en cuenta que los nombres de los campos y los métodos también deben empezar por mayúscula si queremos acceder a dichos campos o métodos, en caso contrario tendremos una estructura de la que no podremos leer datos ni ejecutar métodos.

Para que el módulo siga la estructura de un proyecto en Go, inicializamos un módulo.

mkdir structureTest
cd structureTest
go mod init structureTest

El primer paso será mover las estructuras a otro package y crear los métodos.

mkdir structures
vi structures/structures.go

package structures

import "fmt"

type person struct {
    Name string
    Age  int
    Sex  string
}

func (p person) PersonMethod() {
    fmt.Println("personMethod accessed")
}

type student struct {
    person
    Grade string
}

func (s student) StudentMethod() {
    fmt.Println("studentMethod accessed")
}

// New code, uppercase to make it available from outside current package
func NewStudent(name string, age int, sex, grade string) (student, error) {
    newStudent := student{}
    if len(name) > 0 && age > 18 && age < 120 && (sex == "Male" || sex == "Female") && len(grade) > 0 {
        newStudent = student {
            person: person{
                Name: name,
                Age:  age,
                Sex:  sex,
            },
            Grade: grade,
        }
        return newStudent, nil
    } else {
        return newStudent, fmt.Errorf("Error: Incorrect student data input.")
    }
}

type teacher struct {
    person
    TeachingYears int
}

func (t teacher) TeacherMethod() {
    fmt.Println("teacherMethod accessed")
}

// New code, uppercase to make it available from outside current package
func NewTeacher(name string, age int, sex string, teachingYears int) (teacher, error) {
    newTeacher := teacher{}
    if len(name) > 0 && age > 18 && age < 120 && (sex == "Male" || sex == "Female") && teachingYears > 0 {
        newTeacher = teacher {
            person: person{
                Name: name,
                Age:  age,
                Sex:  sex,
            },
            TeachingYears: teachingYears,
        }
        return newTeacher, nil
    } else {
        return newTeacher, fmt.Errorf("Error: Incorrect teacher data input.")
    }
}

Ahora desde el fichero principal debemos importar el package y llamar al método para instanciar el estudiante y el maestro.

vi structureTest.go

package main

import (
    "fmt"
    "structureTest/structures"
)

func main() {
    student, err := structures.NewStudent("Ana", 20, "Female", "engineering")
    if err != nil {
        fmt.Println("Error obtaining structures.NewStudent:", err)
        return
    }
    teacher, err := structures.NewTeacher("Joe", 30, "Male", 10)
    if err != nil {
        fmt.Println("Error obtaining structures.NewTeacher:", err)
        return
    }

    fmt.Println(student)
    fmt.Println("Name: ", student.Name)
    fmt.Println("Age: ", student.Age)
    fmt.Println("Sex: ", student.Sex)
    fmt.Println("Grade: ", student.Grade)
    student.PersonMethod()
    student.StudentMethod()

    fmt.Println("-----")

    fmt.Println(teacher)
    fmt.Println("Name: ", teacher.Name)
    fmt.Println("Age: ", teacher.Age)
    fmt.Println("Sex: ", teacher.Sex)
    fmt.Println("TeachingYears: ", teacher.TeachingYears)
    teacher.PersonMethod()
    teacher.TeacherMethod()

    fmt.Println("-----")
    student2, err := structures.NewStudent("", 20, "Female", "engineering")
    if err != nil {
        fmt.Println("Error obtaining structures.NewStudent:", err)
        return
    }
    fmt.Println(student2)
}

Ejecutando el código podemos ver que funciona sin problemas, incluso no permite crear un alumno con el nombre vacío.

go run structureTest.go

{{Ana 20 Female} engineering}
Name:  Ana
Age:  20
Sex:  Female
Grade:  engineering
personMethod accessed
studentMethod accessed
-----
{{Joe 30 Male} 10}
Name:  Joe
Age:  30
Sex:  Male
TeachingYears:  10
personMethod accessed
teacherMethod accessed
-----
Error obtaining structures.NewStudent: Error: Incorrect student data input.

La encapsulación no se limita al momento de instanciación de objetos, también puede utilizarse para realizar lecturas(getters) o escrituras(setters) de los campos de una estructura, esto nos permitirá programar una lógica de lecturas y escrituras de campos totalmente personalizada.

Para ello los campos de la estructura deben estar en minúsculas para que sean privados y debemos escribir un métodos para leer/setear valores. Los nombres idiomáticos de los getters/setters es el nombre del campo para los getters y SetNOMBRECAMPO para los setters.

vi structures/structures.go
package structures

import "fmt"

type person struct {
    name string
    age  int
    sex  string
}

func (p person) PersonMethod() {
    fmt.Println("personMethod accessed")
}

type student struct {
    person
    grade string
}

func (s student) StudentMethod() {
    fmt.Println("studentMethod accessed")
}

func (s student) Name() string {
    return s.name
}

func (s student) Age() int {
    return s.age
}

func (s student) Sex() string {
    return s.sex
}

func (s student) Grade() string {
    return s.grade
}

func (s *student) SetName(newName string) {
    s.name = newName
}

func (s *student) SetAge(newAge int) {
    s.age = newAge
}

func (s *student) SetSex(newSex string) {
    s.sex = newSex
}

func (s *student) SetGrade(newGrade string) {
    s.grade = newGrade
}

func NewStudent(name string, age int, sex, grade string) (student, error) {
    newStudent := student{}
    if len(name) > 0 && age > 18 && age < 120 && (sex == "Male" || sex == "Female") && len(grade) > 0 {
        newStudent = student{
            person: person{
                name: name,
                age:  age,
                sex:  sex,
            },
            grade: grade,
        }
        return newStudent, nil
    } else {
        return newStudent, fmt.Errorf("Error: Incorrect student data input.")
    }
}

type teacher struct {
    person
    teachingYears int
}

func (t teacher) TeacherMethod() {
    fmt.Println("teacherMethod accessed")
}

func (t teacher) Name() string {
    return t.name
}

func (t teacher) Age() int {
    return t.age
}

func (t teacher) Sex() string {
    return t.sex
}

func (t teacher) TeachingYears() int {
    return t.teachingYears
}

func (t *teacher) SetName(newName string) {
    t.name = newName
}

func (t *teacher) SetAge(newAge int) {
    t.age = newAge
}

func (t *teacher) SetSex(newSex string) {
    t.sex = newSex
}

func (t *teacher) SetTeachingYears(newteachingYears int) {
    t.teachingYears = newteachingYears
}

func NewTeacher(name string, age int, sex string, teachingYears int) (teacher, error) {
    newTeacher := teacher{}
    if len(name) > 0 && age > 18 && age < 120 && (sex == "Male" || sex == "Female") && teachingYears > 0 {
        newTeacher = teacher{
            person: person{
                name: name,
                age:  age,
                sex:  sex,
            },
            teachingYears: teachingYears,
        }
        return newTeacher, nil
    } else {
        return newTeacher, fmt.Errorf("Error: Incorrect teacher data input.")
    }
}
vi structureTest.go
package main

import (
    "fmt"
    "structureTest/structures"
)

func main() {
    student, err := structures.NewStudent("Ana", 20, "Female", "engineering")
    if err != nil {
        fmt.Println("Error obtaining structures.NewStudent:", err)
        return
    }
    teacher, err := structures.NewTeacher("Joe", 30, "Male", 10)
    if err != nil {
        fmt.Println("Error obtaining structures.NewTeacher:", err)
        return
    }

    fmt.Println(student)
    fmt.Println("Name: ", student.Name())
    fmt.Println("Age: ", student.Age())
    fmt.Println("Sex: ", student.Sex())
    fmt.Println("Grade: ", student.Grade())
    student.PersonMethod()
    student.StudentMethod()

    fmt.Println("-----")

    fmt.Println(teacher)
    fmt.Println("Name: ", teacher.Name())
    fmt.Println("Age: ", teacher.Age())
    fmt.Println("Sex: ", teacher.Sex())
    fmt.Println("Grade: ", teacher.TeachingYears())
    teacher.PersonMethod()
    teacher.TeacherMethod()

    fmt.Println("--- Resetting student --")

    student.SetName("Kevin Mitnick")
    student.SetAge(66)
    student.SetSex("Male")
    student.SetGrade("Hacker")

    fmt.Println(student)
    fmt.Println("Name: ", student.Name())
    fmt.Println("Age: ", student.Age())
    fmt.Println("Sex: ", student.Sex())
    fmt.Println("Grade: ", student.Grade())
    student.PersonMethod()
    student.StudentMethod()

    fmt.Println("--- Resetting teacher --")

    teacher.SetName("Richard Stallman")
    teacher.SetAge(99)
    teacher.SetSex("Male")
    teacher.SetTeachingYears(20)

    fmt.Println(teacher)
    fmt.Println("Name: ", teacher.Name())
    fmt.Println("Age: ", teacher.Age())
    fmt.Println("Sex: ", teacher.Sex())
    fmt.Println("Grade: ", teacher.TeachingYears())
    teacher.PersonMethod()
    teacher.TeacherMethod()
}

Ejecutando el código podemos ver que sigue funcionando, pero esta vez se accede a los valores a través de loe getters y se cambian los valores a través de los setters:

go run structureTest.go

{{Ana 20 Female} engineering}
Name:  Ana
Age:  20
Sex:  Female
Grade:  engineering
personMethod accessed
studentMethod accessed
-----
{{Joe 30 Male} 10}
Name:  Joe
Age:  30
Sex:  Male
Grade:  10
personMethod accessed
teacherMethod accessed
--- Resetting student --
{{Kevin Mitnick 66 Male} Hacker}
Name:  Kevin Mitnick
Age:  66
Sex:  Male
Grade:  Hacker
personMethod accessed
studentMethod accessed
--- Resetting teacher --
{{Richard Stallman 99 Male} 20}
Name:  Richard Stallman
Age:  99
Sex:  Male
Grade:  20
personMethod accessed
teacherMethod accessed

Comparar estructuras:

Las estructuras se podrán comparar siempre y cuando tengan el mismo número y tipo de campos.

vi 05-structures.go
package main

import (
    "fmt"
)

type name struct {
    firstName string
    lastName  string
}

func main() {
    name1 := name{
        firstName: "Steve",
        lastName:  "Jobs",
    }
    name2 := name{
        firstName: "Steve",
        lastName:  "Jobs",
    }
    if name1 == name2 {
        fmt.Println("name1 and name2 are equal")
    } else {
        fmt.Println("name1 and name2 are not equal")
    }

    name3 := name{
        firstName: "Steve",
        lastName:  "Jobs",
    }
    name4 := name{
        firstName: "Steve",
    }

    if name3 == name4 {
        fmt.Println("name3 and name4 are equal")
    } else {
        fmt.Println("name3 and name4 are not equal")
    }
}
go run 05-structures.go
name1 and name2 are equal
name3 and name4 are not equal

Pero si algún campo no es comparable, como ocurre con los maps que no es posible compararlos, obtendremos un error.

vi 06-structures.go
package main

import (
    "fmt"
)

type image struct {
    data map[int]int
}

func main() {
    image1 := image{
        data: map[int]int{
            0: 155,
        }}
    image2 := image{
        data: map[int]int{
            0: 155,
        }}
    if image1 == image2 {
        fmt.Println("image1 and image2 are equal")
    }
}
go run 06-structures.go
./06-structures.go:20:8: invalid operation: image1 == image2 (struct containing map[int]int cannot be compared)
Si te ha gustado el artículo puedes invitarme a un RedBull aquí