Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
结构体表示一项记录,比如保存图书馆的书籍记录,每本书有以下属性:
结构体定义需要使用 type 和 struct 语句。struct 语句定义一个新的数据类型,结构体有中有一个或多个成员。type 语句设定了结构体的名称。结构体的格式如下:
type struct_variable_type struct {
member definition;
member definition;
...
member definition;
}
一旦定义了结构体类型,它就能用于变量的声明,语法格式如下:
variable_name := structure_variable_type {value1, value2...valuen}
如果要访问结构体成员,需要使用点号 (.) 操作符,格式为:"结构体.成员名"。 结构体类型变量使用 struct 关键字定义,实例如下:
package main
import "fmt"
type Books struct {
title string
author string
subject string
book_id int
}
func main() {
var Book1 Books /* 声明 Book1 为 Books 类型 */
var Book2 Books /* 声明 Book2 为 Books 类型 */
/* book 1 描述 */
Book1.title = "Go 语言"
Book1.author = "wek "
Book1.subject = "Go 语言教程"
Book1.book_id = 6495407
/* book 2 描述 */
Book2.title = "Python 教程"
Book2.author = "wek"
Book2.subject = "Python 语言教程"
Book2.book_id = 6495700
/* 打印 Book1 信息 */
fmt.Printf( "Book 1 title : %s\n", Book1.title)
fmt.Printf( "Book 1 author : %s\n", Book1.author)
fmt.Printf( "Book 1 subject : %s\n", Book1.subject)
fmt.Printf( "Book 1 book_id : %d\n", Book1.book_id)
/* 打印 Book2 信息 */
fmt.Printf( "Book 2 title : %s\n", Book2.title)
fmt.Printf( "Book 2 author : %s\n", Book2.author)
fmt.Printf( "Book 2 subject : %s\n", Book2.subject)
fmt.Printf( "Book 2 book_id : %d\n", Book2.book_id)
}
结果为:
Book 1 title : Go 语言
Book 1 author : wek
Book 1 subject : Go 语言教程
Book 1 book_id : 6495407
Book 2 title : Python 教程
Book 2 author : wek
Book 2 subject : Python 语言教程
Book 2 book_id : 6495700
你可以像其他数据类型一样将结构体类型作为参数传递给函数。
你可以定义指向结构体的指针类似于其他指针变量,格式如下:
var struct_pointer *Books
以上定义的指针变量可以存储结构体变量的地址。查看结构体变量地址,可以将 & 符号放置
于结构体变量前:
struct_pointer = &Book1;
使用结构体指针访问结构体成员,使用 "." 操作符:
struct_pointer.title;
切片是 Go 语言中的关键数据类型,为序列提供了比数组更强大的接口。与数组不同,切片(slice)只是由它们包含的元素(而不是元素的数量)键入。要创建 非零长度的空切片,请使用内置 make()函数。 我们可以像数组一样设置和获取字符串的子串值。len()函数返回切片的长度。 除了这些基本操作之外,切片还支持更多,使它们比数组更丰富。一个是内 置 append()函数,它返回包含一个或多个新值的切片。注意,需要接收 append()函数的返回值,因为可能得到一个新的 slice 值。 也可以复制切片。这里创建一个与切片 s 相同长度的空切片 c,并从切片 s 复制到 c 中。切片支持具有语法为 slice[low:high]的切片运算符。 例如,这获得元素 s[2],s[3]和 s[4]的切片。 这切片到(但不包括)s[5]。这切片从(包括)s[2]。可以在一行中声明并初始化slice 的变量。 切片可以组成多维数据结构。内切片的长度可以变化,与多维数组不同。
var identifier []type
切片不需要说明长度。 或使用 make()函数来创建切片:
var slice1 []type = make([]type, len)
也可以简写为
slice1 := make([]type, len)
也可以指定容量,其中 capacity 为可选参数。
make([]T, length, capacity)
这里 len 是数组的长度并且也是切片的初始长度。
直接初始化切片,[]表示是切片类型,{1,2,3}初始化值依次是 1,2,3.其 cap=len=3
s :=[] int {1,2,3 }
初始化切片s,是数组arr的引用
s := arr[:]
将 arr 中从下标 startIndex 到 endIndex-1 下的元素创建为一个新的切片
s := arr[startIndex:]
缺省 endIndex 时将表示一直到 arr 的最后一个元素
s := arr[:endIndex]
缺省 startIndex 时将表示从 arr 的第一个元素开始
s1 := s[startIndex:endIndex]
通过切片 s 初始化切片 s1
s :=make([]int,len,cap)
通过内置函数 make()初始化切片 s,[]int 标识为其元素类型为 int 的切片
切片是可索引的,并且可以由 len() 方法获取长度。 切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。
一个切片在未初始化之前默认为 nil,长度为 0
package main
import "fmt"
func main() {
var numbers []int
printSlice(numbers)
if(numbers == nil){ fmt.Printf("切片是空的")
}
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
结果为:
len=0 cap=0 slice=[] 切片是空的
如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来。 下面的代码描述了从拷贝切片的 copy 方法和向切片追加新元素的 append 方法。
package main
import "fmt"
func main() {
var numbers []int
printSlice(numbers)
/* 允许追加空切片 */
numbers = append(numbers, 0)
printSlice(numbers)
/* 向切片添加一个元素 */
numbers = append(numbers, 1)
printSlice(numbers)
/* 同时添加多个元素 */
numbers = append(numbers, 2,3,4)
printSlice(numbers)
/* 创建切片 numbers1 是之前切片的两倍容量*/
numbers1 := make([]int, len(numbers), (cap(numbers))*2)
/* 拷贝 numbers 的内容到 numbers1 */
copy(numbers1,numbers)
printSlice(numbers1)
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
结果为:
len=0 cap=0 slice=[]
len=1 cap=1 slice=[0]
len=2 cap=2 slice=[0 1]
len=5 cap=6 slice=[0 1 2 3 4]
len=5 cap=12 slice=[0 1 2 3 4]
Go 语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合
(map)的元素。在数组和切片中它返回元素的索引值,在集合中返回 key-value 对的 key 值。
package main
import "fmt"
func main() { //这是我们使用 range 去求一个 slice 的和。使用数组跟这个很类似
nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
sum += num
}
fmt.Println("sum:", sum) //在数组上使用 range 将传入 index 和值两个变量。上面那个例子我们不需要使用该元素的序号, 所以我们使用空白符"_"省略了。有时侯我们确实需要知道它的索引。
for i, num := range nums {
if num == 3 {
fmt.Println("index:", i)
}
} //range 也可以用在 map 的键值对上。
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
} //range 可以只迭代 map 的 key 值
for k := range kvs {
fmt.Println("key:", k)
}
//range 也可以用来枚举 Unicode 字符串。第一个参数是字符的索引,第二个是字符(Unicode 的 值)本身。
for i, c := range "go" {
fmt.Println(i, c)
}
}
结果为:
sum: 9
index: 1
a -> apple
b -> banana
key: a
key: b
0 103
1 111
Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似
于索引,指向数据的值。 Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。
定义Map
可以使用内建函数 make 也可以使用 map 关键字来定义 Map:
/* 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type
/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)
如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对
package main
import "fmt"
func main() {
var countryCapitalMap map[string]string /* 创建集合 */
countryCapitalMap = make(map[string]string)
/* map 插入 key-value 对,各个国家对应的首都 */
countryCapitalMap["France"] = "Paris"
countryCapitalMap["Italy"] = "Rome"
countryCapitalMap["Japan"] = "Tokyo"
countryCapitalMap["India"] = "New Delhi"
/* 使用 key 输出 map 值 */
for country := range countryCapitalMap {
fmt.Println("Capital of",country,"is",countryCapitalMap[country])
}
/* 查看元素在集合中是否存在 */
captial, ok := countryCapitalMap["United States"] /* 如果 ok 是 true, 则存在,否则不存在 */
if(ok){
fmt.Println("Capital of United States is", captial)
}else {
fmt.Println("Capital of United States is not present")
}
}
结果为:
Capital of France is Paris
Capital of Italy is Rome
Capital of Japan is Tokyo
Capital of India is New Delhi
Capital of United States is not present
delete()函数
delete() 函数用于删除集合的元素, 参数为 map 和其对应的 key。实例如下:
package main
import "fmt"
func main() { /* 创建 map */
countryCapitalMap := map[string] string {"France":"Paris","Italy":"Rome","Japan":
"Tokyo","India":"New Delhi"}
fmt.Println("原始 map")
/* 打印 map */
for country := range countryCapitalMap {
fmt.Println("Capital of",country,"is",countryCapitalMap[country])
}
/* 删除元素 */
delete(countryCapitalMap,"France");
fmt.Println("Entry for France is deleted")
fmt.Println("删除元素后 map")
/* 打印 map */
for country := range countryCapitalMap {
fmt.Println("Capital of",country,"is",countryCapitalMap[country])
}
}
原始 map
Capital of France is Paris
Capital of Italy is Rome
Capital of Japan is Tokyo
Capital of India is New Delhi
Entry for France is deleted 删除元素后 map
Capital of Italy is Rome
Capital of Japan is Tokyo
Capital of India is New Delhi