Hàm (Functions)

Cú pháp hàm cơ bản

func tênHàm(thamSo1 kiểu1, thamSo2 kiểu2) kiểuTrảVề {
    return giáTrị
}

// Ví dụ
func congHai(a, b int) int {   // a và b cùng kiểu: viết gộp
    return a + b
}

Nhiều giá trị trả về — Tính năng đặc trưng của Go

// Hàm trả về (kết quả, lỗi) — pattern phổ biến nhất
func chia(a, b float64) (float64, error) {
    if b == 0 {
        return 0, fmt.Errorf("không thể chia cho 0")
    }
    return a / b, nil
}

// Cách dùng
ket, err := chia(10, 3)
if err != nil {
    fmt.Println("Lỗi:", err)
    return
}
fmt.Printf("10 / 3 = %.4f\n", ket)

Named Return Values

func minMax(nums []int) (min, max int) {
    min, max = nums[0], nums[0]
    for _, n := range nums[1:] {
        if n < min { min = n }
        if n > max { max = n }
    }
    return  // "naked return" — trả về min và max
}

Hàm Variadic (tham số biến đổi)

func tong(nums ...int) int {
    s := 0
    for _, n := range nums {
        s += n
    }
    return s
}

tong(1, 2, 3)        // 6
tong(1, 2, 3, 4, 5)  // 15

// Truyền slice vào variadic function
nums := []int{1, 2, 3}
tong(nums...)  // spread slice

Hàm là giá trị hạng nhất (First-class)

// Gán hàm vào biến
double := func(x int) int { return x * 2 }
fmt.Println(double(5)) // 10

// Truyền hàm làm tham số
func apply(nums []int, f func(int) int) []int {
    result := make([]int, len(nums))
    for i, n := range nums {
        result[i] = f(n)
    }
    return result
}

doubled := apply([]int{1, 2, 3}, double) // [2, 4, 6]

Closure

func taoBodem() func(int) int {
    tong := 0              // biến này được "closure" bắt lấy
    return func(x int) int {
        tong += x
        return tong
    }
}

bodem := taoBodem()
fmt.Println(bodem(5))  // 5
fmt.Println(bodem(3))  // 8
fmt.Println(bodem(2))  // 10

defer — Trì hoãn thực thi

func docFile(path string) error {
    f, err := os.Open(path)
    if err != nil { return err }
    defer f.Close()  // đảm bảo luôn đóng file dù hàm kết thúc thế nào

    // xử lý file...
    return nil
}

// Nhiều defer: thực thi theo thứ tự LIFO (vào sau ra trước)
func demo() {
    defer fmt.Println("1")  // in sau cùng
    defer fmt.Println("2")  // in thứ hai
    defer fmt.Println("3")  // in đầu tiên
    fmt.Println("bắt đầu")
}
// Output: bắt đầu / 3 / 2 / 1
example.go
package main

import (
	"errors"
	"fmt"
)

// Closure: bộ đếm với bước nhảy tuỳ chỉnh
func taoBodem(buocNhay int) func() int {
	n := 0
	return func() int {
		n += buocNhay
		return n
	}
}

// Nhiều return values + error
func sqrt(x float64) (float64, error) {
	if x < 0 {
		return 0, errors.New("không lấy căn số âm")
	}
	// Newton's method
	z := x / 2
	for i := 0; i < 10; i++ {
		z -= (z*z - x) / (2 * z)
	}
	return z, nil
}

func main() {
	// Closure demo
	dem2 := taoBodem(2)
	dem5 := taoBodem(5)
	for i := 0; i < 4; i++ {
		fmt.Printf("dem2=%d  dem5=%d\n", dem2(), dem5())
	}

	// Error handling
	for _, x := range []float64{4, 9, -1, 2} {
		if r, err := sqrt(x); err != nil {
			fmt.Printf("sqrt(%.0f): lỗi - %v\n", x, err)
		} else {
			fmt.Printf("sqrt(%.0f) = %.4f\n", x, r)
		}
	}
}