|
| 1 | +# 2.4 struct |
| 2 | + |
| 3 | +## struct |
| 4 | + |
| 5 | +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`. |
| 6 | +``` |
| 7 | + type persona struct { |
| 8 | + nombre string |
| 9 | + edad int |
| 10 | + } |
| 11 | +``` |
| 12 | +Mira que fácil es definir un `struct`! |
| 13 | + |
| 14 | +Tiene dos campos. |
| 15 | + |
| 16 | +- `nombre` es una `string` usada para guardar el nombre de personas. |
| 17 | +- `edad` es un `int` usado para guardar la de edad de personas. |
| 18 | + |
| 19 | +Vamos a ver como usarlo. |
| 20 | +``` |
| 21 | + type persona struct { |
| 22 | + nombre string |
| 23 | + edad int |
| 24 | + } |
| 25 | +``` |
| 26 | + var P persona // p es de tipo persona |
| 27 | + |
| 28 | + P.nombre = "Astaxie" // asigna "Astaxie" al campo 'nombre' de p |
| 29 | + P.edad = 25 // asigna 25 al campo 'edad' de p |
| 30 | + fmt.Printf("El nombre de la persona es %s\n", P.name) // accedemos al campo 'nombre' de p |
| 31 | + |
| 32 | +Tenemos tres formas mas de definir un struct. |
| 33 | + |
| 34 | +- Asignando un valor inicial en forma ordenada |
| 35 | + |
| 36 | + P := persona{"Tom", 25} |
| 37 | + |
| 38 | +- Usando el formato `campo:valor` para inicializarlo sin orden |
| 39 | + |
| 40 | + P := persona{edad:24, nombre:"Bob"} |
| 41 | + |
| 42 | +- Definimos una struct anónima, y la inicializamos |
| 43 | + |
| 44 | + P := struct{nombre string; edad int}{"Amy",18} |
| 45 | + |
| 46 | +Vamos a ver un ejemplo completo. |
| 47 | +``` |
| 48 | + package main |
| 49 | + import "fmt" |
| 50 | +
|
| 51 | + // definimos un tipo nuevo |
| 52 | + type persona struct { |
| 53 | + nombre string |
| 54 | + edad int |
| 55 | + } |
| 56 | +
|
| 57 | + // comparamos la edad de dos personas, y devolvemos la mas vieja con la |
| 58 | + // diferencia, struct es pasado por valor |
| 59 | + func Older(p1, p2 persona) (persona, int) { |
| 60 | + if p1.edad>p2.edad { |
| 61 | + return p1, p1.edad-p2.edad |
| 62 | + } |
| 63 | + return p2, p2.edad-p1.edad |
| 64 | + } |
| 65 | +
|
| 66 | + func main() { |
| 67 | + var tom persona |
| 68 | +
|
| 69 | + // inicialización |
| 70 | + tom.nombre, tom.edad = "Tom", 18 |
| 71 | +
|
| 72 | + // inicializamos los dos valores con el formato "campo:valor" |
| 73 | + bob := persona{edad:25, nombre:"Bob"} |
| 74 | +
|
| 75 | + // inicializamos los dos valores en orden |
| 76 | + paul := persona{"Paul", 43} |
| 77 | +
|
| 78 | + tb_Older, tb_diff := Older(tom, bob) |
| 79 | + tp_Older, tp_diff := Older(tom, paul) |
| 80 | + bp_Older, bp_diff := Older(bob, paul) |
| 81 | +
|
| 82 | + fmt.Printf("De %s y %s, %s es mas viejo por %d años\n", tom.nombre, bob.nombre , tb_Older.nombre , tb_diff) |
| 83 | +
|
| 84 | + fmt.Printf("De %s y %s, %s es mas viejo por %d años\n", tom.nombre, paul.nombre, tp_Older.nombre, tp_diff) |
| 85 | +
|
| 86 | + fmt.Printf("De %s y %s, %s es mas viejo por %d años\n", bob.nombre, paul.nombre, bp_Older.nombre, bp_diff) |
| 87 | + } |
| 88 | +``` |
| 89 | +### Campos incrustados en un struct |
| 90 | + |
| 91 | +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. |
| 92 | + |
| 93 | +Cuando el campo incrustado es un struct, todos los campos de ese struct serán campos del nuevo struct de forma implícita. |
| 94 | + |
| 95 | +Vamos a ver un ejemplo. |
| 96 | +``` |
| 97 | + package main |
| 98 | + import "fmt" |
| 99 | +
|
| 100 | + type Human struct { |
| 101 | + name string |
| 102 | + age int |
| 103 | + weight int |
| 104 | + } |
| 105 | +
|
| 106 | + type Student struct { |
| 107 | + Human // campo incrustado, esto significa que el struct Student va a incluir los campos que tiene Human. |
| 108 | + speciality string |
| 109 | + } |
| 110 | +
|
| 111 | + func main() { |
| 112 | + // inicializamos a student |
| 113 | + mark := Student{Human{"Mark", 25, 120}, "Computer Science"} |
| 114 | +
|
| 115 | + // campos accesibles |
| 116 | + fmt.Println("Su nombre es ", mark.name) |
| 117 | + fmt.Println("Su edad es ", mark.age) |
| 118 | + fmt.Println("Su peso es ", mark.weight) |
| 119 | + fmt.Println("Su especialidad es ", mark.speciality) |
| 120 | + // modificamos un campo |
| 121 | + mark.speciality = "AI" |
| 122 | + fmt.Println("Mark cambio su especialidad") |
| 123 | + fmt.Println("Su especialidad es ", mark.speciality) |
| 124 | + // modificamos su edad |
| 125 | + fmt.Println("Mark esta mas viejo") |
| 126 | + mark.age = 46 |
| 127 | + fmt.Println("Su edad es ", mark.age) |
| 128 | + // modificamos su peso |
| 129 | + fmt.Println("Mark ya no es mas un atleta") |
| 130 | + mark.weight += 60 |
| 131 | + fmt.Println("Su peso es ", mark.weight) |
| 132 | + } |
| 133 | +``` |
| 134 | + |
| 135 | + |
| 136 | +Figure 2.7 Herencia en Student y Human |
| 137 | + |
| 138 | +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! |
| 139 | + |
| 140 | + mark.Human = Human{"Marcus", 55, 220} |
| 141 | + mark.Human.age -= 1 |
| 142 | + |
| 143 | +Todos los tipos pueden ser utilizados como campos incrustados. |
| 144 | +``` |
| 145 | + package main |
| 146 | + import "fmt" |
| 147 | +
|
| 148 | + type Skills []string |
| 149 | +
|
| 150 | + type Human struct { |
| 151 | + name string |
| 152 | + age int |
| 153 | + weight int |
| 154 | + } |
| 155 | +
|
| 156 | + type Student struct { |
| 157 | + Human // struct como un campo incrustado |
| 158 | + Skills // string como un campo incrustado |
| 159 | + int // usamos un tipo embebido como un campo incrustado |
| 160 | + speciality string |
| 161 | + } |
| 162 | +
|
| 163 | + func main() { |
| 164 | + // inicializamos al Student Jane |
| 165 | + jane := Student{Human:Human{"Jane", 35, 100}, speciality:"Biology"} |
| 166 | + // accedemos a sus campos |
| 167 | + fmt.Println("Su nombre es ", jane.name) |
| 168 | + fmt.Println("Su edad es , jane.age) |
| 169 | + fmt.Println("Su peso es ", jane.weight) |
| 170 | + fmt.Println("Su especialidad es ", jane.speciality) |
| 171 | + // modificamos el valor del campo skill |
| 172 | + jane.Skills = []string{"anatomy"} |
| 173 | + fmt.Println("Sus habilidades son ", jane.Skills) |
| 174 | + fmt.Println("Ella adquirió don habilidades mas ") |
| 175 | + jane.Skills = append(jane.Skills, "physics", "golang") |
| 176 | + fmt.Println("Sus habilidades ahora son ", jane.Skills) |
| 177 | + // modificamos un campo embebido |
| 178 | + jane.int = 3 |
| 179 | + fmt.Println("Su numero preferido es ", jane.int) |
| 180 | + } |
| 181 | +``` |
| 182 | +En el ejemplo anterior, podemos ver que a todos los tipos se les pueden incrustar campos y podemos utilizar funciones para operarlos. |
| 183 | + |
| 184 | +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? |
| 185 | + |
| 186 | +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. |
| 187 | +``` |
| 188 | + package main |
| 189 | + import "fmt" |
| 190 | +
|
| 191 | + type Human struct { |
| 192 | + name string |
| 193 | + age int |
| 194 | + phone string // Human tiene el campo phone |
| 195 | + } |
| 196 | +
|
| 197 | + type Employee struct { |
| 198 | + Human // campo embebido Human |
| 199 | + speciality string |
| 200 | + phone string // phone en employee |
| 201 | + } |
| 202 | +
|
| 203 | + func main() { |
| 204 | + Bob := Employee{Human{"Bob", 34, "777-444-XXXX"}, "Designer", "333-222"} |
| 205 | + fmt.Println("El teléfono del trabajo de Bob es:", Bob.phone) |
| 206 | + // accedemos al campo phone en Human |
| 207 | + fmt.Println("El teléfono personal de Bob es:", Bob.Human.phone) |
| 208 | + } |
| 209 | +``` |
| 210 | +## Enlaces |
| 211 | + |
| 212 | +- [Indice](preface.md) |
| 213 | +- Sección anterior: [Sentencias de control y funciones](02.3.md) |
| 214 | +- Siguiente sección: [Orientado a objetos](02.5.md) |
0 commit comments