map
在go语言中,map
是一个hash 表的引用。
map
的声明
ages := make(map[string]int) // mapping from strings to ints
ages := map[string]int{
"alice": 31,
"charlie": 34,
}
元素的访问
ages["alice"] = 32
fmt.Println(ages["alice"]) // "32"
删除元素
delete(ages, "alice") // remove element ages["alice"]
即使key
不存在,所有上面的这些操作都是安全的。在go语言中,查找一个不存在的key对应的值,返回值类型的0值。
所以下面的操作即使bob
不是ages
的key,仍然代码是没有问题的,因为程序在第一次访问map["bob"]
的时候返回0.
ages["bob"] = ages["bob"] + 1 // happy birthday!
在go语言中不能取map的地址,因为随着数据长度的增加,map的数据可能会转移,所以地址会改。
遍历map
for name, age := range ages {
fmt.Printf("%s\t%d\n", name, age)
}
判断key是否存在
if age, ok := ages["bob"]; !ok { /* ... */
}
判断两个map是否相同只能自己实现
func equal(x, y map[string]int) bool {
if len(x) != len(y) {
return false
}
for k, xv := range x {
if yv, ok := y[k]; !ok || yv != xv {
return false
}
}
return true
}
统计unicode字符
func main() {
counts := make(map[rune]int)
// counts of Unicode characters
var utflen [utf8.UTFMax + 1]int // count of lengths of UTF-8 encodings
invalid := 0
// count of invalid UTF-8 characters
in := bufio.NewReader(os.Stdin)
for {
r, n, err := in.ReadRune() // returns rune, nbytes, error
if err == io.EOF {
break
}
if err != nil {
fmt.Fprintf(os.Stderr, "charcount: %v\n", err)
os.Exit(1)
}
if r == unicode.ReplacementChar && n == 1 {
invalid++
continue
}
counts[r]++
utflen[n]++
}
fmt.Printf("rune\tcount\n")
for c, n := range counts {
fmt.Printf("%q\t%d\n", c, n)
}
fmt.Print("\nlen\tcount\n")
for i, n := range utflen {
if i > 0 {
fmt.Printf("%d\t%d\n", i, n)
}
}
if invalid > 0 {
fmt.Printf("\n%d invalid UTF-8 characters\n", invalid)
}
}
利用map实现图
map的值类型可以也是map类型,下面代码例子中,graph
的key类型是string,值类型是map[string]bool
,表示一个string列表。
var graph = make(map[string]map[string]bool)
func addEdge(from, to string) {
edges := graph[from]
if edges == nil {
edges = make(map[string]bool)
graph[from] = edges
}
edges[to] = true
}
func hasEdge(from, to string) bool {
return graph[from][to]
}
Structs
定义
type Employee struct {
ID int
Name string
Address string
DoB time.Time
Position string
Salary int
ManagerID int
}
var dilbert Employee
成员访问
可以利用.
来访问结构体中的域成员。
dilbert.Salary -= 5000
也可以通过地址访问
position := &dilbert.Position
*position = "Senior " + *position // promoted, for outsourcing to Elbonia
对于结构体的指针也可以使用.
来访问成员
var employeeOfTheMonth *Employee = &dilbert
employeeOfTheMonth.Position += " (proactive team player)"
结构体的域的名称如果是以大写开头的,表示这个成员是可以外部访问的。
package p
type T struct{ a, b int } // a and b are not exported
package q
import "p"
var _ = p.T{a: 1, b: 2} // compile error: can't reference a, b
var _ = p.T{1, 2}
// compile error: can't reference a, b
如果结构体的所有域都是可以比较的,那么这个结构体也是可以比较的。
type Point struct{ X, Y int }
p := Point{1, 2}
q := Point{2, 1}
fmt.Println(p.X == q.X && p.Y == q.Y) // "false"
fmt.Println(p == q)
// "false"