Chuyển tới nội dung chính

Hàm trong Go - Cách tổ chức code thông minh! 🎯

Chào mừng bạn đến với bài học về hàm trong Go! Hàm giống như một công thức nấu ăn - bạn viết một lần và có thể sử dụng lại nhiều lần. Trong bài học này, chúng ta sẽ tìm hiểu cách tạo và sử dụng các hàm trong Go.

Hàm là gì? 🤔

Giống như một công thức nấu ăn:

  • Có tên (tên món ăn)
  • Có nguyên liệu (tham số đầu vào)
  • Có cách làm (code bên trong)
  • Có kết quả (giá trị trả về)

1. Hàm cơ bản (Công thức đơn giản) 📝

func add(x int, y int) int {
return x + y
}

💡 Giải thích:

  • func: Bắt đầu khai báo hàm
  • add: Tên của hàm
  • (x int, y int): Nguyên liệu (tham số đầu vào)
  • int: Kết quả (giá trị trả về)
  • return x + y: Cách làm (code bên trong)

2. Hàm nhiều giá trị trả về (Công thức có nhiều kết quả) 🎯

func divide(x, y float64) (float64, error) {
if y == 0 {
return 0, errors.New("không thể chia cho 0")
}
return x / y, nil
}

💡 Giải thích:

  • Giống như nấu ăn có thể thành công hoặc thất bại
  • Trả về kết quả và thông báo lỗi (nếu có)
  • nil nghĩa là không có lỗi

3. Hàm không có tham số (Công thức không cần nguyên liệu) 🎨

func sayHello() {
fmt.Println("Hello, World!")
}

💡 Giải thích:

  • Giống như một bài hát không cần nhạc cụ
  • Chỉ cần hát là được

4. Hàm với tham số có tên (Công thức có nguyên liệu rõ ràng) 📋

func greet(name string, age int) {
fmt.Printf("Xin chào %s, bạn %d tuổi\n", name, age)
}

💡 Giải thích:

  • Giống như công thức nấu ăn có liệt kê rõ nguyên liệu
  • Dễ hiểu và dễ sử dụng hơn

5. Hàm với tham số không giới hạn (Công thức linh hoạt) 🔄

func sum(numbers ...int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}

💡 Giải thích:

  • Giống như nấu canh có thể cho nhiều loại rau
  • ... nghĩa là có thể nhận nhiều giá trị

6. Hàm closure (Công thức có bí mật) 🤫

func makeCounter() func() int {
count := 0
return func() int {
count++
return count
}
}

💡 Giải thích:

  • Giống như một hộp đếm có thể nhớ số
  • Mỗi lần gọi sẽ tăng số lên 1

7. Hàm method (Công thức gắn với đồ vật) 🎯

type Rectangle struct {
width float64
height float64
}

func (r Rectangle) area() float64 {
return r.width * r.height
}

💡 Giải thích:

  • Giống như cách tính diện tích của một hình chữ nhật
  • Hàm được gắn với một kiểu dữ liệu

8. Hàm với pointer receiver (Công thức thay đổi đồ vật) 🔧

func (r *Rectangle) scale(factor float64) {
r.width *= factor
r.height *= factor
}

💡 Giải thích:

  • Giống như phóng to hoặc thu nhỏ một hình
  • Thay đổi kích thước của hình chữ nhật

9. Hàm với interface (Công thức dùng cho nhiều đồ vật) 🎨

type Shape interface {
area() float64
}

func printArea(s Shape) {
fmt.Printf("Diện tích: %f\n", s.area())
}

💡 Giải thích:

  • Giống như cách tính diện tích cho nhiều loại hình
  • Hình tròn, hình chữ nhật đều có thể dùng

10. Hàm anonymous (Công thức không tên) 🎭

func main() {
func() {
fmt.Println("Hàm anonymous")
}()
}

💡 Giải thích:

  • Giống như một công thức chỉ dùng một lần
  • Không cần đặt tên

11. Hàm với defer (Công thức dọn dẹp) 🧹

func readFile() {
file, err := os.Open("file.txt")
if err != nil {
return
}
defer file.Close()

// Đọc file
}

💡 Giải thích:

  • Giống như việc dọn dẹp sau khi nấu ăn
  • defer đảm bảo việc dọn dẹp luôn được thực hiện

Best Practices (Cách viết hàm tốt) 🌟

1. Đặt tên hàm rõ ràng

// ✅ Tốt
func calculateTotalPrice(items []Item) float64 {
// code
}

// ❌ Không tốt
func calc(items []Item) float64 {
// code
}

💡 Lý do: Giúp người khác dễ hiểu mục đích của hàm

2. Giữ hàm ngắn gọn

// ✅ Tốt
func add(x, y int) int {
return x + y
}

// ❌ Không tốt
func complexCalculation(x, y int) int {
// code dài và phức tạp
}

💡 Lý do: Dễ đọc và dễ bảo trì hơn

3. Xử lý lỗi rõ ràng

// ✅ Tốt
func divide(x, y float64) (float64, error) {
if y == 0 {
return 0, errors.New("không thể chia cho 0")
}
return x / y, nil
}

// ❌ Không tốt
func divide(x, y float64) float64 {
return x / y // Có thể gây lỗi
}

💡 Lý do: Giúp người dùng biết khi nào có lỗi

Những lỗi thường gặp và cách sửa 🔧

  1. Lỗi: Quên return trong hàm có giá trị trả về

    // ❌ Sai
    func add(x, y int) int {
    x + y // Thiếu return
    }

    // ✅ Đúng
    func add(x, y int) int {
    return x + y
    }
  2. Lỗi: Không xử lý lỗi

    // ❌ Sai
    file, _ := os.Open("file.txt") // Bỏ qua lỗi

    // ✅ Đúng
    file, err := os.Open("file.txt")
    if err != nil {
    return err
    }
  3. Lỗi: Sử dụng biến toàn cục trong hàm

    // ❌ Sai
    var globalVar int
    func process() {
    globalVar = 42 // Không nên sử dụng biến toàn cục
    }

    // ✅ Đúng
    func process() int {
    localVar := 42
    return localVar
    }

Tiếp theo 🎯

Trong bài học tiếp theo, chúng ta sẽ:

  • Tìm hiểu về structs (cấu trúc dữ liệu)
  • Học cách tổ chức code thành packages
  • Khám phá cách xử lý lỗi nâng cao

💡 Lời khuyên: Hãy thử viết các hàm đơn giản và sử dụng chúng trong chương trình của bạn để hiểu rõ hơn về cách chúng hoạt động!