Ngôn ngữ Go cung cấp một cấu trúc dữ liệu được gọi là mảng, có thể lưu trữ một tập hợp các phần tử tuần tự có kích thước cố định cùng kiểu với nhau. Một mảng thường được sử dụng để lưu trữ tập hợp dữ liệu, nhưng chúng ta có thể nghĩ theo hướng hữu ích hơn, một mảng giống như là một tập hợp các biến cùng kiểu.
Thay vì khai báo các biến cụ thể như là number0, number1, …, và number99, bạn khai báo một mảng numbers và sử dụng numbers[0], numbers[1], …, numbers[99] để tượng trưng cho các biến cụ thể. Phần tử cụ thể trong mảng được xác định bằng các index.
Tất cả các mảng bao gồm các vị trí bộ nhớ liên tiếp. Địa chỉ thấp nhất tương ứng với phần tử đầu tiên của mảng, và địa chỉ cao nhất là phần tử cuối cùng.
Khai báo mảng
Để khai báo một mảng trong Go, lập trình viên cần chỉ định kiểu của các phần tử, và số các phần tử được yêu cầu trong mảng
var tên_biến [Kích_thước] kiểu_biến
Ví dụ chúng ta có thể khai báo một mảng gồm 10 phần tử số nguyên
var a[10]int
Hãy cùng xem ví dụ sau đây
package main import "fmt" func main() { var x [5]int // Mảng 5 phần tử số nguyên fmt.Println(x) var y [8]string // mảng 8 phần tử string fmt.Println(y) var z [3]complex128 // mảng 3 phần tử complex fmt.Println(z) }
Kết quả
[0 0 0 0 0] [ ] [(0+0i) (0+0i) (0+0i)]
Mặc định tất cả các phần tử của mảng được khởi tạo bằng 0, tùy theo kiểu dữ liệu của mảng.
Ví dụ nếu chúng ta khởi tạo một mảng số nguyên thì tất cả các phần tử đều được khởi tạo bằng 0. Nếu chúng ta khai báo một mảng string thì tất cả các phần tử được khởi tạo là string rỗng ""
Truy cập phần tử trong mảng bằng index
Các phần tử của mảng được lưu trữ tuần tự và có thể được truy cập bằng index. index bắt đầu bằng 0 và kết thúc bằng độ dài mảng – 1.
package main import "fmt" func main() { var x [5]int // Mảng gồm 5 phần tử số nguyên x[0] = 100 x[1] = 101 x[3] = 103 x[4] = 105 fmt.Printf("x[0] = %d, x[1] = %d, x[2] = %d\n", x[0], x[1], x[2]) fmt.Println("x = ", x) }
Kết quả
x[0] = 100, x[1] = 101, x[2] = 0 x = [100 101 0 103 105]
Trong ví dụ ở trên, vì chúng ta không gán giá trị cho phần tử x[2]
, nên nó có giá trị bằng 0.
Khởi tạo mảng sử dụng literal
Bạn có thể khai báo một mảng như sau
var a = [5]int{2, 4, 6, 8, 10}
Cách khai báo mảng như trên được gọi là array literal
Chú ý rằng bạn không cần chỉ định cho kiểu của biến như là var a [5] int
, bởi vì trình biên dịch sẽ tự suy luận ra dựa theo biểu thức bên phải.
Bạn cũng có thể sử dụng cách khai báo biến ngắn gọn của Go và khởi tạo một mảng như sau
a := [5]int{2, 4, 6, 8, 10}
Hãy xem ví dụ đầy đủ sau đây
package main import "fmt" func main() { // Khai báo và khởi tạo mảng cùng một lúc. var a = [5]int{2, 4, 6, 8, 10} fmt.Println(a) // Khai báo ngắn gọn và khởi tạo mảng. b := [5]int{2, 4, 6, 8, 10} fmt.Println(b) // Bạn không cần khởi tạo toàn bộ phần tử của mảng // Các phẩn tử không được khởi tạo sẽ được gán bằng 0 dựa theo kiểu của mảng c := [5]int{2} fmt.Println(c) }
Cho phép trình biên dịch suy luận kích thước mảng
Bạn cũng có thể bỏ qua việc khai báo kích thước mảng từ biểu thức khởi tạo mảng, và để trình biên dịch đếm số phần tử của mảng
package main import "fmt" func main() { // để trình biên dịch suy luận ra kích thước của mảng a := [...]int{3, 5, 7, 9, 11, 13, 17} fmt.Println(a) }
Kết quả
[3 5 7 9 11 13 17]
Độ dài mảng là một phần của kiểu
Độ dài của một mảng là một phần của kiểu. Nên mảng a[5]int
và a[10]int
là 2 kiểu hoàn toàn khác biệt, do đó bạn không thể gán hai mảng cho nhau.
Điều này nghĩa là bạn không thể thay đổi kích thước của một mảng, bởi vì khi bạn thay đổi kích thước của một mảng nghĩa là thay đổi kiểu của nó, và bạn không thể thay đổi kiểu của một biến trong Go
package main func main() { var a = [5]int{3, 5, 7, 9, 11} var b [10]int = a // Lỗi, a và b là 2 kiểu khác biệt }
Mảng trong Go là kiểu giá trị
Mảng trong Go là kiểu giá trị, không giống như các ngôn ngữ khác như là C, C++, và Java mảng là kiểu tham chiếu.
Điều này nghĩa là khi bạn gán mảng cho một biến mới hoặc truyền một mảng cho một hàm, toàn bộ mảng được sao chép. Nên nếu bạn thay đổi bất cứ thông tin gì trong mảng được sao chép này, thì mảng gốc ban đầu sẽ không bị ảnh hưởng và không bị thay đổi.
package main import "fmt" func main() { a1 := [5]string{"English", "Japanese", "Spanish", "French", "Hindi"} a2 := a1 // sao chép mảng `a1` và gán cho `a2` a2[1] = "German" fmt.Println("a1 = ", a1) // mảng `a1` không thay đổi. fmt.Println("a2 = ", a2) }
Kết quả
a1 = [English Japanese Spanish French Hindi] a2 = [English German Spanish French Hindi]
Lặp trên một mảng
Bạn có thể sử dụng vòng lặp for
để lặp trên một mảng trong Go.
package main import "fmt" func main() { names := [3]string{"Mark Zuckerberg", "Bill Gates", "Larry Page"} for i := 0; i < len(names); i++ { fmt.Println(names[i]) } }
Kết quả
Mark Zuckerberg Bill Gates Larry Page
Hàm len()
được sử dụng để tìm độ dài của mảng.
Hãy cùng xem ví dụ sau đây, tính tổng tất cả phần tử trong mảng bằng cách lặp từng phần tử trong mảng và cộng các phần tử với nhau vào biến sum
package main import "fmt" func main() { a := [4]float64{3.5, 7.2, 4.8, 9.5} sum := float64(0) for i := 0; i < len(a); i++ { sum = sum + a[i] } fmt.Printf("Sum of all the elements in array %v = %f\n", a, sum) }
Kết quả
Sum of all the elements in array [3.5 7.2 4.8 9.5] = 25.000000
Lặp trên mảng sử dụng range
Go cung cấp một hình thức mạng mẽ hơn cho vòng lặp for
sử dụng toán tử range
. Sau đây là cách bạn sử dụng toán tử range
với vòng lặp for
để lặp các phần tử trong mảng.
package main import "fmt" func main() { daysOfWeek := [7]string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"} for index, value := range daysOfWeek { fmt.Printf("Day %d of week = %s\n", index, value) } }
Kết quả
Day 0 of week = Mon Day 1 of week = Tue Day 2 of week = Wed Day 3 of week = Thu Day 4 of week = Fri Day 5 of week = Sat Day 6 of week = Sun
Hãy cùng viết lại phần ví dụ bên trên, tính tổng các phần tử trong mảng sử dụng toán tử range
package main import "fmt" func main() { a := [4]float64{3.5, 7.2, 4.8, 9.5} sum := float64(0) for index, value := range a { sum = sum + value } fmt.Printf("Sum of all the elements in array %v = %f", a, sum) }
Kết quả
./array_iteration_range.go:9:13: index declared and not used
Trình biên dịch Go sẽ không cho phép tạo một biến mà không bao giờ sử dụng, bạn có thể sử dụng dấu _
thay cho index
để trình biên dịch biết rằng đây là biến không sử dụng
package main import "fmt" func main() { a := [4]float64{3.5, 7.2, 4.8, 9.5} sum := float64(0) for _, value := range a { sum = sum + value } fmt.Printf("Sum of all the elements in array %v = %f", a, sum) }
Kết quả
Sum of all the elements in array [3.5 7.2 4.8 9.5] = 25.000000
Mảng đa chiều trong Go
Tất cả các mảng mà chúng ta đã tạo cho đến giờ trong bài viết này đều là mảng một chiều. Bạn cũng có thể tạo mảng đa chiều trong Go.
Hãy cùng xem ví dụ sau đây
package main import "fmt" func main() { a := [2][2]int{ {3, 5}, {7, 9}, // Dấu phẩy này là bắt buộc } fmt.Println(a) // Giống như mảng một chiều, bạn không cần phải khởi tạo tất cả các phần tử trong mảng đa chiều // Các phần tử không được khởi tạo sẽ được gán bằng 0 dựa theo kiểu dữ liệu b := [3][4]float64{ {1, 3}, {4.5, -3, 7.4, 2}, {6, 2, 11}, } fmt.Println(b) }
Kết quả
[[3 5] [7 9]] [[1 3 0 0] [4.5 -3 7.4 2] [6 2 11 0]]