Skip to content

Latest commit

 

History

History
214 lines (169 loc) · 6.58 KB

File metadata and controls

214 lines (169 loc) · 6.58 KB

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

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