[Golang cơ bản] Vòng lặp for-range trong golang

Post on: 2023-04-04 00:17:22 | in: Golang
Trong Golang, vòng lặp for-range được sử dụng để lặp qua các phần tử của một slice, một map hoặc một channel.

Tổng quan

Như chúng ta đã biết golang có hai loại vòng lặp là:

  • Vòng lặp for
  • Vòng lặp for-range

Trong bài học trước, chúng ta đã học về vòng lặp "for". Trong bài học này, chúng ta sẽ chỉ tập trung vào học vòng lặp "for-range".

Vòng lặp "for-range" được sử dụng để lặp qua các cấu trúc dữ liệu tập hợp khác nhau trong Golang như:

  • array hoặc slice
  • string
  • maps
  • channel

Bây giờ chúng ta hãy xem một số ví dụ.

Ví dụ

Vòng lặp "for-range" cho array/slice

Đây là cú pháp của vòng lặp "for-range" khi sử dụng với array/slice

for index, value := range array/slice {
    //Do something with index and value
}

Đây là cách hoạt động của vòng lặp "for-range" khi sử dụng với array/slice. Nó duyệt qua array/slice cho trước, bắt đầu từ chỉ số 0 và phần thân của vòng lặp for range được thực thi cho mỗi giá trị có trong mảng tại chỉ số đó. Cả chỉ số và giá trị đều là tùy chọn khi sử dụng với array/slice.

Dưới đây là một số ví dụ cho cách sử dụng vòng lặp "for-range" với mảng/slice:

  • Với cả chỉ số và giá trị
  • Chỉ với giá trị
  • Chỉ với chỉ số
  • Không có chỉ số và giá trị
package main

import "fmt"

func main() {
    letters := []string{"a", "b", "c"}

    //With index and value
    fmt.Println("Both Index and Value")
    for i, letter := range letters {
        fmt.Printf("Index: %d Value:%s\n", i, letter)
    }

    //Only value
    fmt.Println("\nOnly value")
    for _, letter := range letters {
        fmt.Printf("Value: %s\n", letter)
    }

    //Only index
    fmt.Println("\nOnly Index")
    for i := range letters {
        fmt.Printf("Index: %d\n", i)
    }

    //Without index and value. Just print array values
    fmt.Println("\nWithout Index and Value")
    i := 0
    for range letters {
        fmt.Printf("Index: %d Value: %s\n", i, letters[i])
        i++
    }
}

Output:

Both Index and Value
Index: 0 Value:a
Index: 1 Value:b
Index: 2 Value:c

Only value
Value: a
Value: b
Value: c

Only Index
Index: 0
Index: 1
Index: 2

Without Index and Value
Index: 0 Value: a
Index: 1 Value: b
Index: 2 Value: c

Vòng lặp for-range với một chuỗi(string)

Trong Golang, chuỗi là một chuỗi các byte. Một chuỗi văn bản trong Go thực chất là một chuỗi các byte theo định dạng UTF-8. Trong định dạng UTF-8, các ký tự ASCII là các byte đơn tương ứng với 128 ký tự Unicode đầu tiên. Tất cả các ký tự khác có độ dài từ 1 đến 4 byte. Để hiểu rõ hơn, hãy xem ví dụ sau về chuỗi:

sample := "a£c"

Trong chuỗi trên

  • ‘a’ chiếm một byte theo UTF-8
  • '£' chiếm hai byte theo UTF-8
  • 'b' chiếm một byte theo UTF-8

Chuỗi trên có tổng cộng 1 + 2 + 1 = 4 byte. Do đó, khi chúng ta cố gắng in độ dài của chuỗi bằng cách sử dụng hàm tiêu chuẩn len (), nó sẽ đưa ra đầu ra là 4 và không phải là 3 vì hàm len () trả về số byte trong chuỗi.

fmt.Printf("Length is %d\n", len(sample))

Đoạn văn nói về việc lặp với for không thể được sử dụng để duyệt qua tất cả các ký tự của một chuỗi vì nó sẽ duyệt qua các byte và không phải ký tự. Vì vậy vòng lặp for dưới đây sẽ lặp qua bốn lần và in ra giá trị tương ứng với byte có mặt tại chỉ mục đó.

for i := 0; i < len(sample); i++ {
    fmt.Printf("%c\n", sample[i])
}

Nó sẽ xuất ra chuỗi dưới đây mà không giống với chuỗi "a£c"

a£b

Đầu ra trên không phải là những gì chúng ta muốn. Đây là lúc for-range loop xuất hiện để giải quyết vấn đề khi sử dụng với chuỗi. Nó lặp lại các điểm Unicode (còn được gọi là rune trong golang) trong một chuỗi và sẽ đưa ra đúng a, £, b. Đây là định dạng khi sử dụng for-range với chuỗi

for index, character := range string {
    //Do something with index and character
}

Có một số điểm cần lưu ý trước khi chúng ta chuyển sang ví dụ

  • index là điểm bắt đầu của ký tự Unicode trong chuỗi. Ví dụ trong chuỗi "a£c", ký tự "a" bắt đầu tại chỉ số 0, ký tự "£" bắt đầu tại chỉ số 1 trong khi ký tự "b" bắt đầu tại chỉ số 3.
  • value là điểm mã Unicode hoặc cơ bản là mỗi ký tự trong chuỗi thay vì các byte. Nó còn được gọi là rune. Một rune trong Golang đại diện cho một Unicode Code Point
  • Cả index và value đều là tùy chọn

Bây giờ hãy xem một ví dụ

package main

import "fmt"

func main() {
    sample := "a£b"

    //With index and value
    fmt.Println("Both Index and Value")
    for i, letter := range sample {
        fmt.Printf("Start Index: %d Value:%s\n", i, string(letter))
    }

    //Only value
    fmt.Println("\nOnly value")
    for _, letter := range sample {
        fmt.Printf("Value:%s\n", string(letter))
    }

    //Only index
    fmt.Println("\nOnly Index")
    for i := range sample {
        fmt.Printf("Start Index: %d\n", i)
    }
}

Output:

Both Index and Value
Start Index: 0 Value:a
Start Index: 1 Value:£
Start Index: 3 Value:b

Only value
Value:a
Value:£
Value:b
​​​​​​​
Only Index
Start Index: 0
Start Index: 1
Start Index: 3

Vòng lặp for-range với một map

Trong trường hợp của map, for-range lặp qua các key và value trong một map. Dưới đây là định dạng cho vòng lặp for-range khi sử dụng với map

for key, value := range map {
    //Do something with key and value
}

Một điểm cần lưu ý là cả key và value đều có thể được bỏ qua khi sử dụng vòng lặp for-range với maps. Hãy xem một ví dụ code đơn giản.

package main

import "fmt"

func main() {
    sample := map[string]string{
        "a": "x",
        "b": "y",
    }

    //Iterating over all keys and values
    fmt.Println("Both Key and Value")
    for k, v := range sample {
        fmt.Printf("key :%s value: %s\n", k, v)
    }

    //Iterating over only keys
    fmt.Println("\nOnly keys")
    for k := range sample {
        fmt.Printf("key :%s\n", k)
    }
​​​​​​​
    //Iterating over only values
    fmt.Println("\nOnly values")
    for _, v := range sample {
        fmt.Printf("value :%s\n", v)
    }
}

Output

Both Key and Value
key :a value: x
key :b value: y

Only keys
key :a
key :b
​​​​​​​
Only values
value :x
value :y

Vòng lặp for-range với một channel

Đoạn văn này nói rằng vòng lặp for-range hoạt động khác nhau đối với một kênh (channel). Đối với một kênh, chỉ số không có ý nghĩa gì vì kênh tương tự như một đường ống, trong đó các giá trị nhập từ một đầu và xuất ra từ đầu kia.

Do đó, đối với kênh, vòng lặp for-range sẽ lặp lại qua các giá trị hiện có trong kênh. Sau khi nó đã lặp lại qua tất cả các giá trị hiện có (nếu có), vòng lặp for-range sẽ không thoát mà thay vào đó đợi cho giá trị tiếp theo có thể được đẩy vào kênh và nó chỉ thoát khi kênh bị đóng.

Dưới đây là định dạng khi sử dụng vòng lặp for-range với channel

for value := range channel {
    //Do something value
}

Hãy xem một ví dụ

package main

import "fmt"
​​​​​​​
func main() {
    ch := make(chan string)
    go pushToChannel(ch)
    for val := range ch {
        fmt.Println(val)
    }
}
func pushToChannel(ch chan<- string) {
    ch <- "a"
    ch <- "b"
    ch <- "c"
    close(ch)
}

Output:

a
b
c

Tổng kết

Đó là tất cả về vòng lặp for-range trong golang. Hy vọng bạn thích nó. Vui lòng chia sẻ phản hồi / cải tiến / sai sót trong bình luận.

Tag: golang cơ bản go