Bài học theo mô-đun (4/5)
Đóng cửa và chức năng như giá trị
Trong Go, các hàm là giá trị hạng nhất: chúng có thể được gán cho các biến, được chuyển đến các hàm khác và được trả về. đóng cửa là một hàm theo nghĩa đen (ẩn danh) nắm bắt các biến của môi trường mà nó được xác định.
Chức năng theo nghĩa đen
Một hàm không có tên, được viết nội tuyến. Bạn gọi nó ngay lập tức hoặc chỉ định nó:
greet := func(name string) {
fmt.Println("ciao", name)
}
greet("Anna")
// invocata immediatamente:
func() { fmt.Println("subito") }()Loại greet là func(string).
Nắm bắt môi trường: đóng cửa
Hàm đen có thể đọc và sửa đổi các biến hiển thị trong phạm vi từ vựng của nó, ngay cả sau khi hàm bên ngoài đã trả về:
func counter() func() int {
n := 0
return func() int {
n++
return n
}
}
c := counter()
fmt.Println(c(), c(), c()) // 1 2 3n "tồn tại" miễn là có ít nhất một lần đóng tham chiếu đến nó. Mỗi cuộc gọi đến
counter() tạo n mới, độc lập.
Đóng cửa dưới dạng gọi lại
Một mô hình rất phổ biến:
nums := []int{3, 1, 2}
sort.Slice(nums, func(i, j int) bool {
return nums[i] < nums[j]
})Việc đóng sẽ ghi lại nums và xác định thứ tự.
Chức năng như tham số
Để chấp nhận một hàm làm tham số, hãy viết ra kiểu của nó:
func apply(nums []int, f func(int) int) []int {
out := make([]int, len(nums))
for i, n := range nums {
out[i] = f(n)
}
return out
}
double := func(x int) int { return x * 2 }
apply([]int{1, 2, 3}, double) // [2 4 6]Nếu chữ ký trở nên khó đọc, hãy xác định loại bí danh:
type Transform func(int) int
func apply(nums []int, f Transform) []int { ... }Hãy thử nó
Xác định counter() trả về một bao đóng: mỗi lệnh gọi đến bao đóng sẽ tăng dần và trả về một bộ đếm nội bộ.
Hiển thị gợi ý
`n` phải được khai báo TRƯỚC KHI trả về; việc đóng cửa nắm bắt nó.
Giải pháp khả dụng sau 3 lần thử
Gán cho f một chữ hàm in 'ciao', sau đó gọi nó.
Hiển thị gợi ý
Cú pháp: `f := func() { ... }` rồi `f()`.
Giải pháp khả dụng sau 3 lần thử
Cái này in cái gì? (coi chừng phạm vi đóng cửa)
mk := func() func() int {
x := 0
return func() int { x++; return x }
}
a := mk()
b := mk()
fmt.Println(a(), a(), b())Tóm tắt lại
- Chức năng hạng nhất: có thể gán, có thể vượt qua, có thể trả về.
- Hàm ý:
func(params) ret { ... }, ẩn danh. - Closure: nắm bắt các biến thuộc phạm vi từ vựng, giữ cho chúng tồn tại.
- Kiểu hàm rõ ràng trong tham số:
func(int) int. - Kể từ Go 1.22, mỗi lần lặp for đều có bản sao của biến vòng lặp.