Go – Map

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

 

You May Also Like

About the Author: Nguyen Dinh Thuc

Leave a Reply

Your email address will not be published.