← Go EspañolChapter 08 of 13

Structs y Métodos

## Objetivos de Aprendizaje - Definir y usar structs - Crear e inicializar instancias de struct - Trabajar con campos de struct - Definir métodos con receptores - Comprender receptores de valor vs puntero - Incrustar structs para composición ## Structs ### Definición ```go type Person struct { Name string Age int City string } ``` ### Declaración ```go var p Person // Inicializado a cero p := Person{} // También inicializado a cero p := Person{Name: "Alice", Age: 30} // Con nombres de campos p := Person{"Alice", 30, "NYC"} // Posicional (frágil) ``` ### Acceso a Campos ```go p := Person{Name: "Alice", Age: 30} fmt.Println(p.Name) // Alice fmt.Println(p.Age) // 30 p.Age = 31 // Modificar campo fmt.Println(p.Age) // 31 ``` ## Creando Instancias ### Valor Cero ```go var p Person // Todos los campos con valor cero fmt.Println(p) // { 0 } ``` ### Literal Compuesto ```go p := Person{ Name: "Alice", Age: 30, } ``` ### Operador new ```go p := new(Person) // Retorna *Person (puntero) p.Name = "Bob" // No se necesita sintaxis de flecha fmt.Println(p) // &{Bob 0} ``` ### Puntero a Literal ```go p := &Person{Name: "Carol", Age: 25} fmt.Println(p) // &{Carol 25} ``` ## Struct con Punteros ```go type Node struct { Value int Next *Node } n1 := &Node{Value: 1} n2 := &Node{Value: 2} n1.Next = n2 fmt.Println(n1.Next.Value) // 2 ``` ## Métodos ### Receptor de Valor ```go type Rectangle struct { Width, Height float64 } func (r Rectangle) Area() float64 { return r.Width * r.Height } func main() { r := Rectangle{Width: 10, Height: 5} fmt.Println(r.Area()) // 50 } ``` ### Receptor de Puntero ```go type Rectangle struct { Width, Height float64 } func (r *Rectangle) Scale(factor float64) { r.Width *= factor r.Height *= factor } func main() { r := Rectangle{Width: 10, Height: 5} r.Scale(2) fmt.Println(r.Width, r.Height) // 20 10 } ``` ### Cuándo Usar Punteros | Situación | Recomendación | |-----------|----------------| | Modificar el receptor | Usar `*T` | | Mutar un objeto grande | Usar `*T` | | Asegurar consistencia | Usar `*T` | | Método de solo lectura | Usar `T` o `*T` | ## Tipos Nombrados ### Definición de Tipo ```go type Celsius float64 type Fahrenheit float64 func (c Celsius) ToFahrenheit() Fahrenheit { return Fahrenheit(c*9/5 + 32) } func main() { var c Celsius = 100 fmt.Printf("%.2f C = %.2f F\n", c, c.ToFahrenheit()) } ``` ## Structs Incrustados (Composición) ### Incrustación Básica ```go type Address struct { Street string City string State string } type Person struct { Name string Address // Incrustado (sin nombre de campo) } func main() { p := Person{ Name: "Alice", Address: Address{ Street: "123 Main St", City: "NYC", State: "NY", }, } fmt.Println(p.Street) // Acceso directo (promovido) fmt.Println(p.Address.Street) // También funciona } ``` ### Sombreado ```go type A struct { x int } type B struct { A x int // Sombrea A.x } func main() { b := B{A: A{x: 1}, x: 2} fmt.Println(b.x) // 2 (x de B) fmt.Println(b.A.x) // 1 (x de A) } ``` ## Tags de Struct ### Definición de Tag de Struct ```go type Person struct { Name string `json:"name"` Age int `json:"age"` } ``` ### Tags Comunes ```go type Person struct { Name string `json:"name" xml:"name"` Age int `json:"age,omitempty"` } ``` ### Acceder a Tags ```go import "reflect" t := reflect.TypeOf(Person{}) field, _ := t.FieldByName("Name") fmt.Println(field.Tag.Get("json")) // name ``` ## Comparando Structs ### Comparables Los structs son comparables si todos sus campos son comparables. ```go type Point struct { X, Y int } p1 := Point{1, 2} p2 := Point{1, 2} if p1 == p2 { fmt.Println("Iguales") } ``` ### Con Campos No Comparables ```go type Person struct { Name string Slice []int // No comparable } p1 := Person{Name: "Alice"} p2 := Person{Name: "Alice"} // p1 == p2 // ERROR DE COMPILACIÓN ``` ## Función vs Método ### Función ```go func area(r Rectangle) float64 { return r.Width * r.Height } ``` ### Método ```go func (r Rectangle) area() float64 { return r.Width * r.Height } ``` ## Diseño de Memoria ### Padding ```go type Foo struct { A int8 // 1 byte _ [7]byte // padding B int64 // 8 bytes } type Bar struct { B int64 // 8 bytes A int8 // 1 byte _ [7]byte // padding } ``` ### El Orden Importa Poner campos más grandes primero para minimizar padding: ```go type Efficient struct { B int64 // 8 bytes A int8 // 1 byte C int32 // 4 bytes } ``` ## Patrones Comunes ### Patrón Constructor ```go type Stack struct { items []int } func NewStack() *Stack { return &Stack{items: make([]int, 0)} } func (s *Stack) Push(item int) { s.items = append(s.items, item) } ``` ### Patrón Opción ```go type Server struct { Port int Timeout int } type Option func(*Server) func WithPort(port int) Option { return func(s *Server) { s.Port = port } } func NewServer(opts ...Option) *Server { s := &Server{Port: 8080, Timeout: 30} for _, opt := range opts { opt(s) } return s } func main() { s := NewServer(WithPort(9090)) } ``` ## Resumen - Los structs agrupan campos relacionados - Usar literales compuestos para inicializar: `Person{Name: "Alice"}` - `new(Type)` retorna puntero a struct inicializado a cero - Los métodos tienen receptores - usar receptor de puntero para modificar - Los structs incrustados proporcionan composición (sin herencia) - Los tags de struct anotan campos para codificación/decodificación - El orden de campos de struct afecta el diseño de memoria - Usar funciones constructor para inicialización compleja

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →