Go 没有变量值为空、null 或 undefined 的概念。 声明变量时如果没有显式指定初始值,变量会默认为其对应类型的零值。
布尔、数字和字符串等基本类型的零值分别是false、0和""。
标识符nil意为零,它是指针、函数、接口、切片、通道和映射等更复杂类型的零值。
下表详细列出了 Go 各类型的零值。
| 类型 | 零值 |
|---|---|
| 布尔 | false |
| 数字 | 0 |
| 字符串 | "" |
| 指针 | nil |
| 函数 | nil |
| 接口 | nil |
| 切片 | nil |
| 通道 | nil |
| 映射 | nil |
你可能已经注意到,上表中没有结构体类型。 这是因为结构体类型的零值取决于它的字段。 当结构体的所有字段都被设为其各自的零值时,结构体就被设为其零值。
你的任务是让这座城市的 IT 系统为即将到来的人口普查做好准备。 具体来说,你负责编写处理普查员收集的数据的程序。
该程序必须能在给定居民信息时,在系统中创建一位新居民。 此外,你还要编写一些函数,用来检查居民数据中是否包含必需的信息,以及删除居民的数据。 最后,你要统计居民人数,以得出准确的人口普查数据。
普查员收集居民信息时,需要把居民的姓名、年龄和地址录入系统,完成登记。
实现函数NewResident,它接受三个实参:
该函数应返回一个指向Resident结构体的指针,其中保存着这些信息。
name := "Matthew Sanabria"
age := 29
address := map[string]string{"street": "Main St."}
NewResident(name, age, address)
// => &{Matthew Sanabria 29 map[street:Main St.]}
居民可能不愿意向普查员提供个人信息。 这种情况下,就需要判断该居民是否提供了被纳入人口普查所需的必需信息。
要被统计在内,居民必须为姓名提供一个非零值,并提供street键为非零值的地址。
其他所有信息,例如居民的年龄,都是可选的。
实现HasRequiredInfo方法,返回一个布尔值,表示该居民是否提供了必需信息。
name := "Matthew Sanabria"
age := 0
address := make(map[string]string)
resident := NewResident(name, age, address)
resident.HasRequiredInfo()
// => false
生活变化很快,错误也在所难免。 居民可能会搬离这座城市。 普查员在收集数据时也可能出错。 这些情况下,就需要能够删除居民的数据,让他们不被统计在内。
实现Delete方法,把居民的所有字段都设为其零值。
name := "Matthew Sanabria"
age := 29
address := map[string]string{"street": "Main St."}
resident := NewResident(name, age, address)
fmt.Println(resident)
// Output: &{Matthew Sanabria 29 map[street:Main St.]}
resident.Delete()
fmt.Println(resident)
// Output: &{ 0 map[]}
现在系统已经支持普查数据,是时候进行人口普查并统计居民人数了!
实现函数Count,它接受一个实参:
Resident结构体的指针切片。该函数应返回一个整数,表示在人口普查中被统计的居民人数。 只有当居民向普查员提供了必需信息时,才能被统计在内。
name1 := "Matthew Sanabria"
age1 := 29
address1 := map[string]string{"street": "Main St."}
resident1 := NewResident(name1, age1, address1)
name2 := "Rob Pike"
age2 := 0
address2 := make(map[string]string)
resident2 := NewResident(name2, age2, address2)
residents := []*Resident{resident1, resident2}
Count(residents)
// => 1