Funciones
## Objetivos de Aprendizaje
- Definir y llamar funciones
- Retornar múltiples valores
- Usar funciones variádicas
- Comprender closures
- Pasar funciones como valores
- Usar panic y recover
## Funciones Básicas
### Declaración
```go
func greet(name string) {
fmt.Println("Hola,", name)
}
func main() {
greet("Alice") // Hola, Alice
}
```
### Con Valor de Retorno
```go
func add(a, b int) int {
return a + b
}
func main() {
result := add(3, 5)
fmt.Println(result) // 8
}
```
### Múltiples Parámetros
```go
func greet(firstName, lastName string) {
fmt.Printf("Hola, %s %s\n", firstName, lastName)
}
```
## Múltiples Valores de Retorno
### Retornos Múltiples Básicos
```go
func divide(a, b float64) (float64, float64) {
quotient := a / b
remainder := a - quotient*b
return quotient, remainder
}
func main() {
q, r := divide(10, 3)
fmt.Printf("Cociente: %.2f, Resto: %.2f\n", q, r)
}
```
### Valores de Retorno Nombrados
```go
func rectangleProperties(width, height float64) (area, perimeter float64) {
area = width * height
perimeter = 2 * (width + height)
return // Return desnudo
}
```
### Ignorar Valores de Retorno
```go
quotient, _ := divide(10, 3) // Ignorar resto
```
## Manejo de Errores
### Retornar Errores
```go
func safeDivide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("división por cero")
}
return a / b, nil
}
func main() {
result, err := safeDivide(10, 0)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Resultado:", result)
}
```
### Tipos de Error Personalizados
```go
type DivisionError struct {
Dividend float64
Divisor float64
}
func (e *DivisionError) Error() string {
return fmt.Sprintf("no se puede dividir %.2f por cero", e.Dividend)
}
func safeDivide(a, b float64) (float64, error) {
if b == 0 {
return 0, &DivisionError{Dividend: a, Divisor: b}
}
return a / b, nil
}
```
## Funciones Variádicas
### Variádica Básica
```go
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func main() {
fmt.Println(sum(1, 2, 3)) // 6
fmt.Println(sum(1, 2, 3, 4, 5)) // 15
fmt.Println(sum()) // 0
}
```
### Operador Spread
```go
nums := []int{1, 2, 3, 4, 5}
fmt.Println(sum(nums...)) // 15
```
### Múltiples Variádicas
```go
func concat(separator string, values ...string) string {
result := ""
for i, v := range values {
if i > 0 {
result += separator
}
result += v
}
return result
}
func main() {
fmt.Println(concat("-", "a", "b", "c")) // a-b-c
}
```
## Closures
### Closure Básico
```go
func main() {
add := func(a, b int) int {
return a + b
}
fmt.Println(add(3, 5)) // 8
}
```
### Closure con Estado
```go
func counter() func() int {
count := 0
return func() int {
count++
return count
}
}
func main() {
next := counter()
fmt.Println(next()) // 1
fmt.Println(next()) // 2
fmt.Println(next()) // 3
}
```
### Closure para Caché
```go
func memoize(f func(int) int) func(int) int {
cache := make(map[int]int)
return func(n int) int {
if result, ok := cache[n]; ok {
return result
}
result = f(n)
cache[n] = result
return result
}
}
```
## Funciones como Valores
### Pasar Función como Argumento
```go
func apply(nums []int, fn func(int) int) []int {
result := make([]int, len(nums))
for i, n := range nums {
result[i] = fn(n)
}
return result
}
func main() {
nums := []int{1, 2, 3, 4, 5}
doubled := apply(nums, func(n int) int { return n * 2 })
fmt.Println(doubled) // [2 4 6 8 10]
}
```
### Retornar Función
```go
func multiplier(factor int) func(int) int {
return func(n int) int {
return n * factor
}
}
func main() {
double := multiplier(2)
triple := multiplier(3)
fmt.Println(double(5)) // 10
fmt.Println(triple(5)) // 15
}
```
## Funciones Anónimas
### IIFE (Invocada Inmediatamente)
```go
result := func() int {
sum := 0
for i := 1; i <= 10; i++ {
sum += i
}
return sum
}()
fmt.Println(result) // 55
```
### Parámetros Nombrados
```go
func operate(a, b int, op func(int, int) int) int {
return op(a, b)
}
func main() {
result := operate(10, 5, func(x, y int) int { return x + y })
fmt.Println(result) // 15
}
```
## Recursión
### Recursión Básica
```go
func factorial(n int) int {
if n <= 1 {
return 1
}
return n * factorial(n-1)
}
func main() {
fmt.Println(factorial(5)) // 120
}
```
### Fibonacci Recursivo
```go
func fibonacci(n int) int {
if n <= 1 {
return n
}
return fibonacci(n-1) + fibonacci(n-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
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
}
```
## panic y recover
### panic
```go
func criticalSection() {
defer fmt.Println("Limpieza")
panic("¡Algo salió mal!")
fmt.Println("Esto no se imprimirá")
}
func main() {
criticalSection()
fmt.Println("Esto tampoco se imprimirá")
}
```
### recover
```go
func safeCall() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recuperado de:", r)
}
}()
panic("¡Algo salió mal!")
}
func main() {
safeCall()
fmt.Println("El programa continúa...")
}
```
### Cuándo Usar panic
- Reservado para situaciones verdaderamente irrecuperables
- Errores de programación (ej. desreferencia de puntero nil)
- No para condiciones de error esperadas (usar retornos de error)
## Resumen
- Las funciones se declaran con la palabra clave `func`
- Múltiples valores de retorno para manejo de errores
- Funciones variádicas aceptan argumentos variables con `...`
- Los closures son funciones que capturan su entorno
- Las funciones son ciudadanos de primera clase (pueden pasarse como valores)
- Los métodos son funciones con parámetros receptor
- panic/recover para situaciones excepcionales, no errores normales
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →