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