Go cung cấp kiểu dữ liệu quan trọng khác tên là map. map là một collection không theo thứ tự của cặp từ khoá và giá trị (key – value), dùng để mapping giữa từ khoá và giá trị. Từ khoá là duy nhất trong map, trong khi đó giá trị thì tùy ý. Cấu trúc dữ liệu của map thường được sử dụng để tra cứu nhanh, thu hồi, xóa dữ liệu dựa trên các từ khoá. Nó là một trong những cấu trúc dữ liệu được sử dụng nhiều nhất trong khoa học máy tính.
Khai báo map
map được khai báo sử dụng cú pháp như sau:
var m map[kiểu_key]kiểu_giá_trị
Ví dụ, sau đây là khai báo cho key kiểu string
và giá trị kiểu int
var m map[string]int
Giá trị 0 của map là nil
. nil
map không có từ khoá nào. Ngoài ra, nếu thử thêm từ khoá vào map nil
sẽ dẫn đến một kết quả lỗi khi chạy.
Hãy cùng xem ví dụ sau đây:
package main import "fmt" func main() { var m map[string]int fmt.Println(m) if m == nil { fmt.Println("m is nil") } // nếu thử thêm key vào map nil sẽ dẫn đến một kết quả lỗi khi chạy. // m["one hundred"] = 100 }
Kết quả
map[] m is nil
Nếu bạn bỏ comment câu lệnh m["one hundred"] = 100
chương trình sẽ đưa ra một lỗi như sau.
panic: assignment to entry in nil map
Do đó, cần phải khởi tạo một map trước khi thêm các phần tử vào cho nó.
Khởi tạo map
Khởi tạo map sử dụng hàm make()
Bạn có thể khởi tạo một map sử dụng hàm được tích hợp sẵn make()
. Bạn chỉ cần truyền vào kiểu của map cho hàm make()
như ví dụ bên dưới đây. Hàm sẽ trả về một map đã được khởi tạo và sẵn sàng để sử dụng
var m = make(map[string]int)
Hãy cùng xem ví dụ sau:
package main import "fmt" func main() { var m = make(map[string]int) fmt.Println(m) if m == nil { fmt.Println("m is nil") } else { fmt.Println("m is not nil") } // hàm make() trả về một map đã được khởi tạo và sẵn sàng để sử dụng // do nó được khởi tạo nên có thể thêm key cho nó m["one hundred"] = 100 fmt.Println(m) }
Kết quả
map[] m is not nil map[one hundred:100]
Khởi tạo map sử dụng literal
map literal là một cách tiện lợi để khởi tạo map với một vài dữ liệu. Bạn chỉ cần truyền các cặp từ khoá – giá trị ngăn cách nhau bằng dấu phẩy bên trong dấu ngoặc nhọn như sau:
var m = map[string]int{ "one": 1, "two": 2, "three": 3, }
Chú ý rằng cần có dấu phẩy ở cuối cùng nếu không trình biên dịch sẽ báo lỗi.
Hãy cùng xem ví dụ sau đây:
package main import "fmt" func main() { var m = map[string]int{ "one": 1, "two": 2, "three": 3, "four": 4, "five": 5, // dấu phẩy là cần thiết } fmt.Println(m) }
Kết quả
map[one:1 two:2 three:3 four:4 five:5]
Bạn cũng có thể tạo một map trống sử dụng map literal bằng cách để trống dấu ngoặc nhọn
var m = map[string]int{}
Câu lệnh trên chức năng tương tự như sử dụng hàm make()
.
Thêm các phần tử (cặp từ khoá-giá trị) trong map
Bạn có thể thêm các phần tử mới cho map được khởi tạo sử dụng cú pháp như sau:
m[key] = value
Ví dụ sau khởi tạo một map sử dụng hàm make()
và thêm một vài phần tử mới cho nó
package main import "fmt" func main() { // khởi tạo một map var tinderMatch = make(map[string]string) // thêm key cho map tinderMatch["Rajeev"] = "Angelina" // gán giá trị "Angelina" cho key "Rajeev" tinderMatch["James"] = "Sophia" tinderMatch["David"] = "Emma" fmt.Println(tinderMatch) /* thêm một key đã tồn tại thì đơn giản chỉ là ghi đè giá trị của key đã tồn tại */ tinderMatch["Rajeev"] = "Jennifer" fmt.Println(tinderMatch) }
Kết quả
map[Rajeev:Angelina James:Sophia David:Emma] map[Rajeev:Jennifer James:Sophia David:Emma]
Nếu bạn thử thêm từ khoá mà đã tồn tại thì nó sẽ đơn giản chỉ là ghi đè giá trị của từ khoá đã tồn tại.
Lấy gía trị được liên kết với một từ khoá đã cho trong map
Bạn có thể lấy giá trị được liên kết với một từ khoá đã cho trong map bằng cách sử dụng cú pháp m[key]
. Nếu key tồn tại trong map, bạn sẽ nhận được giá trị được gán. Nếu không, bạn sẽ nhận được giá trị 0 của kiểu giá trị của map.
Hãy cùng xem ví dụ sau đây
package main import "fmt" func main() { var personMobileNo = map[string]string{ "John": "+33-8273658526", "Steve": "+1-8579822345", "David": "+44-9462834443", } var mobileNo = personMobileNo["Steve"] fmt.Println("Steve's Mobile No : ", mobileNo) // Nếu key không tồn tại trong map, chúng ta sẽ nhận được giá trị 0 của kiểu giá trị mobileNo = personMobileNo["Jack"] fmt.Println("Jack's Mobile No : ", mobileNo) }
Kết qủa
Steve's Mobile No : +1-8579822345 Jack's Mobile No :
Trong ví dụ bên trên, do từ khoá “Jack” không tồn tại trong map, nên chúng ta nhận được giá trị 0 của kiểu giá trị, ở đây kiểu string nên giá trị là rỗng. Không giống như các ngôn ngữ khác, chúng ta sẽ không nhận một lỗi nếu từ khoá không tồn tại
Kiểm tra từ khoá tồn tại hay không
Khi bạn muốn lấy giá trị được gán cho một từ khoá cho trước sử dụng cú pháp map[key]
, nó sẽ trả thêm về một giá trị, là true
nếu từ khoá đấy tồn tại trong map, và false
nếu không tồn tại.
Nên bạn có thể kiểm tra từ khoá tồn tại trong map sử dụng gán 2 giá trị như sau:
value, ok := m[key]
Biến boolean ok
sẽ là true
nếu từ khoá tồn tại, ngược lại trả về false
Hãy cùng xem ví dụ sau:
var employees = map[int]string{ 1001: "Rajeev", 1002: "Sachin", 1003: "James", }
Truy cập từ khoá 1001
sẽ trả về "Rajeev"
và true
, do từ khoá 1001
tồn tại trong map.
name, ok := employees[1001] // "Rajeev", true
Tuy nhiên, nếu bạn truy cập từ khoá không tồn tại, thì map sẽ trả về một string rỗng ""
(giá trị 0 của string) và false
.
name, ok := employees[1010] // "", false
Nếu bạn chỉ muốn kiểm tra xem từ khoá có tồn tại hay không mà không muốn lấy giá trị liên kết với từ khoá, thì bạn có thể sử dụng _
cho biến đầu tiên
_, ok := employees[1005]
Nào hãy cùng xem ví dụ sau đây
package main import "fmt" func main() { var employees = map[int]string{ 1001: "John", 1002: "Steve", 1003: "Maria", } printEmployee(employees, 1001) printEmployee(employees, 1010) if isEmployeeExists(employees, 1002) { fmt.Println("EmployeeId 1002 found") } } func printEmployee(employees map[int]string, employeeId int) { if name, ok := employees[employeeId]; ok { fmt.Printf("name = %s, ok = %v\n", name, ok) } else { fmt.Printf("EmployeeId %d not found\n", employeeId) } } func isEmployeeExists(employees map[int]string, employeeId int) bool { _, ok := employees[employeeId] return ok }
Kết quả
name = Rajeev, ok = true EmployeeId 1010 not found EmployeeId 1002 found
Xoá từ khoá khỏi map
Bạn có thể xoá một từ khoá khỏi map sử dụng hàm delete()
được tích hợp sẵn. Cú pháp như sau:
delete(map, key)
Hàm delete() không trả về giá trị. Nó cũng không xử lý gì nếu từ khoá không tồn tại trong map.
Sau đây là toàn bộ ví dụ:
package main import "fmt" func main() { var fileExtensions = map[string]string{ "Python": ".py", "C++": ".cpp", "Java": ".java", "Golang": ".go", "Kotlin": ".kt", } fmt.Println(fileExtensions) delete(fileExtensions, "Kotlin") // Hàm xoá không xử lý gì nếu từ khoá không tồn tại delete(fileExtensions, "Javascript") fmt.Println(fileExtensions) }
Kết quả
map[Python:.py C++:.cpp Java:.java Golang:.go Kotlin:.kt] map[Python:.py C++:.cpp Java:.java Golang:.go]
map là kiểu tham chiếu
map là kiểu tham chiếu. Khi bạn gán một map cho một biến mới, cả hai đều cùng tham chiếu đến một cấu trúc dữ liệu cơ bản. Do đó những thay đổi được thực hiện bởi biến này sẽ ảnh hưởng đến biến còn lại
package main import "fmt" func main() { var m1 = map[string]int{ "one": 1, "two": 2, "three": 3, "four": 4, "five": 5, } var m2 = m1 fmt.Println("m1 = ", m1) fmt.Println("m2 = ", m2) m2["ten"] = 10 fmt.Println("\nm1 = ", m1) fmt.Println("m2 = ", m2) }
Kết quả
m1 = map[one:1 two:2 three:3 four:4 five:5] m2 = map[one:1 two:2 three:3 four:4 five:5] m1 = map[one:1 two:2 three:3 four:4 five:5 ten:10] m2 = map[one:1 two:2 three:3 four:4 five:5 ten:10]
Tương tự nó cũng sẽ được áp dụng khi bạn truyền một map vào một hàm. Mọi thay đổi của map bên trong hàm, cũng anh hưởng đến phía gọi.
Lặp trên map
Bạn có thể thực hiện lặp trên map sử dụng định dạng range
của vòng lặp for
. Nó cung cấp cho bạn cặp từ khoá, giá trị
trong tất cả vòng lặp.
package main import "fmt" func main() { var personAge = map[string]int{ "Rajeev": 25, "James": 32, "Sarah": 29, } for name, age := range personAge { fmt.Println(name, age) } }
Kết quả
James 32 Sarah 29 Rajeev 25