# 2.4 struct ## struct Podemos definir en Go nuevos tipos de contenedores con otras propiedades o campos como en otros lenguajes de programación. Por ejemplo, podemos crear el tipo llamado `persona` para representar una persona, este tipo tiene nombre y edad. Podemos llamar estos tipos de tipos como `struct`. ``` type persona struct { nombre string edad int } ``` Mira que fácil es definir un `struct`! Tiene dos campos. - `nombre` es una `string` usada para guardar el nombre de personas. - `edad` es un `int` usado para guardar la de edad de personas. Vamos a ver como usarlo. ``` type persona struct { nombre string edad int } ``` var P persona // p es de tipo persona P.nombre = "Astaxie" // asigna "Astaxie" al campo 'nombre' de p P.edad = 25 // asigna 25 al campo 'edad' de p fmt.Printf("El nombre de la persona es %s\n", P.nombre) // accedemos al campo 'nombre' de p Tenemos tres formas mas de definir un struct. - Asignando un valor inicial en forma ordenada P := persona{"Tom", 25} - Usando el formato `campo:valor` para inicializarlo sin orden P := persona{edad:24, nombre:"Bob"} - Definimos una struct anónima, y la inicializamos P := struct{nombre string; edad int}{"Amy",18} Vamos a ver un ejemplo completo. ``` package main import "fmt" // definimos un tipo nuevo type persona struct { nombre string edad int } // comparamos la edad de dos personas, y devolvemos la mas vieja con la // diferencia, struct es pasado por valor func Older(p1, p2 persona) (persona, int) { if p1.edad>p2.edad { return p1, p1.edad-p2.edad } return p2, p2.edad-p1.edad } func main() { var tom persona // inicialización tom.nombre, tom.edad = "Tom", 18 // inicializamos los dos valores con el formato "campo:valor" bob := persona{edad:25, nombre:"Bob"} // inicializamos los dos valores en orden paul := persona{"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("De %s y %s, %s es mas viejo por %d años\n", tom.nombre, bob.nombre , tb_Older.nombre , tb_diff) fmt.Printf("De %s y %s, %s es mas viejo por %d años\n", tom.nombre, paul.nombre, tp_Older.nombre, tp_diff) fmt.Printf("De %s y %s, %s es mas viejo por %d años\n", bob.nombre, paul.nombre, bp_Older.nombre, bp_diff) } ``` ### Campos incrustados en un struct Solo les mostré como definir struct con campos que tienen nombre y tipo. De hecho, Go soporta campos sin nombre pero si con tipo, vamos a llamar a estos campos incrustados. Cuando el campo incrustado es un struct, todos los campos de ese struct serán campos del nuevo struct de forma implícita. Vamos a ver un ejemplo. ``` package main import "fmt" type Human struct { name string age int weight int } type Student struct { Human // campo incrustado, esto significa que el struct Student va a incluir los campos que tiene Human. speciality string } func main() { // inicializamos a student mark := Student{Human{"Mark", 25, 120}, "Computer Science"} // campos accesibles fmt.Println("Su nombre es ", mark.name) fmt.Println("Su edad es ", mark.age) fmt.Println("Su peso es ", mark.weight) fmt.Println("Su especialidad es ", mark.speciality) // modificamos un campo mark.speciality = "AI" fmt.Println("Mark cambio su especialidad") fmt.Println("Su especialidad es ", mark.speciality) // modificamos su edad fmt.Println("Mark esta mas viejo") mark.age = 46 fmt.Println("Su edad es ", mark.age) // modificamos su peso fmt.Println("Mark ya no es mas un atleta") mark.weight += 60 fmt.Println("Su peso es ", mark.weight) } ``` ![](images/2.4.student_struct.png?raw=true) Figure 2.7 Herencia en Student y Human Vemos que accedemos a la edad y nombre en Student de la misma forma que lo hacemos con Human. Así es como funcionan los campos incrustados. Es muy útil “cool”, no lo es? Espera, hay algo todavía mas “cool”! Puede utilizar a Student para acceder a los campos incrustados de Human! mark.Human = Human{"Marcus", 55, 220} mark.Human.age -= 1 Todos los tipos pueden ser utilizados como campos incrustados. ``` package main import "fmt" type Skills []string type Human struct { name string age int weight int } type Student struct { Human // struct como un campo incrustado Skills // string como un campo incrustado int // usamos un tipo embebido como un campo incrustado speciality string } func main() { // inicializamos al Student Jane jane := Student{Human:Human{"Jane", 35, 100}, speciality:"Biology"} // accedemos a sus campos fmt.Println("Su nombre es ", jane.name) fmt.Println("Su edad es , jane.age) fmt.Println("Su peso es ", jane.weight) fmt.Println("Su especialidad es ", jane.speciality) // modificamos el valor del campo skill jane.Skills = []string{"anatomy"} fmt.Println("Sus habilidades son ", jane.Skills) fmt.Println("Ella adquirió don habilidades mas ") jane.Skills = append(jane.Skills, "physics", "golang") fmt.Println("Sus habilidades ahora son ", jane.Skills) // modificamos un campo embebido jane.int = 3 fmt.Println("Su numero preferido es ", jane.int) } ``` En el ejemplo anterior, podemos ver que a todos los tipos se les pueden incrustar campos y podemos utilizar funciones para operarlos. Hay un problema mas, si Human tiene un campo llamado `phone` y Student tiene otro campo llamado con el mismo nombre, que deberíamos hacer? Go utiliza una forma muy sencilla para resolverlo. Los campos exteriores consiguen accesos superiores, lo que significa, es que cuando se accede a `student.phone`, obtendremos el campo llamado phone en student, no en el struct de Human. Esta característica se puede ver simplemente como una `sobrecarga` de campos. ``` package main import "fmt" type Human struct { name string age int phone string // Human tiene el campo phone } type Employee struct { Human // campo embebido Human speciality string phone string // phone en employee } func main() { Bob := Employee{Human{"Bob", 34, "777-444-XXXX"}, "Designer", "333-222"} fmt.Println("El teléfono del trabajo de Bob es:", Bob.phone) // accedemos al campo phone en Human fmt.Println("El teléfono personal de Bob es:", Bob.Human.phone) } ``` ## Enlaces - [Índice](preface.md) - Sección anterior: [Sentencias de control y funciones](02.3.md) - Siguiente sección: [Orientado a objetos](02.5.md)