结构体定义需要使用 type 和 struct 语句。struct 语句定义一个新的数据类型,结构体中有一个或多个成员。type 语句设定了结构体的名称。结构体的格式如下:
type struct_variable_type struct { member definition member definition ... member definition }
一旦定义了结构体类型,它就能用于变量的声明,语法格式如下:
variable_name := structure_variable_type {value1, value2...valuen} 或 variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}
示例:
package main import "fmt" type Books struct { title string author string subject string book_id int } func main() { // 创建一个新的结构体 fmt.Println(Books{"Go 语言", "www.runoob.com", "Go 语言教程", 6495407}) // 也可以使用 key => value 格式 fmt.Println(Books{title: "Go 语言", author: "www.runoob.com", subject: "Go 语言教程", book_id: 6495407}) // 忽略的字段为 0 或 空 fmt.Println(Books{title: "Go 语言", author: "www.runoob.com"})
输出结果为:
{Go 语言 www.runoob.com Go 语言教程 6495407} {Go 语言 www.runoob.com Go 语言教程 6495407} {Go 语言 www.runoob.com 0}
结构体定义也是除了写法不同都和C++没什么区别,其中结构体变量声明多了一种key->value的形式。此外,结构体作为函数参数、结构体指针的内容与C++基本相同,这里就不作记录了。
2.Go 语言切片(Slice)Go 语言切片是对数组的抽象。
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
定义切片你可以声明一个未指定大小的数组来定义切片:
var identifier []type
切片不需要说明长度。
或使用 make() 函数来创建切片:
var slice1 []type = make([]type, len) 也可以简写为 slice1 := make([]type, len)
也可以指定容量,其中 capacity 为可选参数。
make([]T, length, capacity)
这里 len 是数组的长度并且也是切片的初始长度。
这里回顾一下不定长数组的定义:
var variable_name [...] variable_type
一个方括号内是“...”一个方括号内为空,注意两者区别。
切片初始化s :=[] int {1,2,3 }
直接初始化切片,[] 表示是切片类型,{1,2,3} 初始化值依次是 1,2,3,其 cap=len=3。
s := arr[:]
初始化切片 s,是数组 arr 的引用。
s := arr[startIndex:endIndex]
将 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() 函数
切片是可索引的,并且可以由 len() 方法获取长度。
切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。
以下为具体实例:
package main import "fmt" func main() { var numbers = make([]int,3,5) printSlice(numbers) } func printSlice(x []int){ fmt.Printf("len=%d cap=%d slice=%vn",len(x),cap(x),x)
以上实例运行输出结果为:
空(nil)切片len=3 cap=5 slice=[0 0 0]
一个切片在未初始化之前默认为 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=%vn",len(x),cap(x),x)
以上实例运行输出结果为:
len=0 cap=0 slice=[] 切片是空的切片截取
可以通过设置下限及上限来设置截取切片 [lower-bound:upper-bound],实例如下:
package main import "fmt" func main() { numbers := []int{0,1,2,3,4,5,6,7,8} printSlice(numbers) fmt.Println("numbers ==", numbers) fmt.Println("numbers[1:4] ==", numbers[1:4]) fmt.Println("numbers[:3] ==", numbers[:3]) fmt.Println("numbers[4:] ==", numbers[4:]) numbers1 := make([]int,0,5) printSlice(numbers1) number2 := numbers[:2] printSlice(number2) number3 := numbers[2:5] printSlice(number3) } func printSlice(x []int){ fmt.Printf("len=%d cap=%d slice=%vn",len(x),cap(x),x)
执行以上代码输出结果为:
append() 和 copy() 函数len=9 cap=9 slice=[0 1 2 3 4 5 6 7 8] numbers == [0 1 2 3 4 5 6 7 8] numbers[1:4] == [1 2 3] numbers[:3] == [0 1 2] numbers[4:] == [4 5 6 7 8] len=0 cap=5 slice=[] len=2 cap=9 slice=[0 1] len=3 cap=7 slice=[2 3 4]
如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来。
下面的代码描述了从拷贝切片的 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 := make([]int, len(numbers), (cap(numbers))*2) copy(numbers1,numbers) printSlice(numbers1) } func printSlice(x []int){ fmt.Printf("len=%d cap=%d slice=%vn",len(x),cap(x),x) }
以上代码执行输出结果为:
3.Go 语言范围(Range)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 对。
for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:
for key, value := range oldMap { newMap[key] = value }
以上代码中的 key 和 value 是可以省略的。
如果只想读取 key,格式如下:
for key := range oldMap //或者 for key, _ := range oldMap
如果只想读取 value,格式如下:
for _, value := range oldMap
遍历简单的数组,2**%d 的结果为索引对应的次方数:
package main import "fmt" var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} func main() { for i, v := range pow { fmt.Printf("2**%d = %dn", i, v) } }
以上实例运行输出结果为:
2**0 = 1 2**1 = 2 2**2 = 4 2**3 = 8 2**4 = 16 2**5 = 32 2**6 = 64 2**7 = 128
range 遍历其他数据结构:
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 将传入索引和值两个变量。上面那个例子我们不需要使用该元素的序号,所以我们使用空白符"_"省略了。有时侯我们确实需要知道它的索引。 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 -> %sn", k, v) } //range也可以用来枚举 Unicode 字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。 for i, c := range "go" { fmt.Println(i, c) } }
以上实例运行输出结果为:
4.Go 语言Map(集合)sum: 9 index: 1 a -> apple b -> banana 0 103 1 111
Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。
定义 Map可以使用内建函数 make 也可以使用 map 关键字来定义 Map:
var map_variable map[key_data_type]value_data_type map_variable := make(map[key_data_type]value_data_type)
如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对
下面实例演示了创建和使用map:
package main import "fmt" func main() { var countryCapitalMap map[string]string countryCapitalMap = make(map[string]string) countryCapitalMap [ "France" ] = "巴黎" countryCapitalMap [ "Italy" ] = "罗马" countryCapitalMap [ "Japan" ] = "东京" countryCapitalMap [ "India " ] = "新德里" for country := range countryCapitalMap { fmt.Println(country, "首都是", countryCapitalMap [country]) } capital, ok := countryCapitalMap [ "American" ] if (ok) { fmt.Println("American 的首都是", capital) } else { fmt.Println("American 的首都不存在") } }
以上实例运行结果为:
delete() 函数France 首都是 巴黎 Italy 首都是 罗马 Japan 首都是 东京 India 首都是 新德里 American 的首都不存在
delete() 函数用于删除集合的元素, 参数为 map 和其对应的 key。实例如下:
package main import "fmt" func main() { countryCapitalMap := map[string]string{"France": "Paris", "Italy": "Rome", "Japan": "Tokyo", "India": "New delhi"} fmt.Println("原始地图") for country := range countryCapitalMap { fmt.Println(country, "首都是", countryCapitalMap [ country ]) } delete(countryCapitalMap, "France") fmt.Println("法国条目被删除") fmt.Println("删除元素后地图") for country := range countryCapitalMap { fmt.Println(country, "首都是", countryCapitalMap [ country ]) } }
以上实例运行结果为:
原始地图 India 首都是 New delhi France 首都是 Paris Italy 首都是 Rome Japan 首都是 Tokyo 法国条目被删除 删除元素后地图 Italy 首都是 Rome Japan 首都是 Tokyo India 首都是 New delhi
Go语言递归函数这一章内容与C++完全相同,这里不作记录。
5.总结Go语言结构体的内容与C++基本相同;map类型其实和C++的STL容器中的map基本相同的,就是在遍历时可以利用range更方便地操作,C++遍历map使用的是迭代器iterator,写起来也会繁琐一些;切片slince和范围range是Go特有的内容,slince可以对已有的数组进行切片,或是直接替代数组的功能,通过设置上限和下限截取数组或者切片是一种很便利的功能,range对各种容器遍历的通用性也可以使编程更加简便。