上一章为大家简单的介绍了字符串的一些内容以及内存地址与指针的一些相关操作,今天为大家介绍的是数据的四种基本类型以及关于函数的一些入门
Go语言提供了数组类型的数据结构。数组是具有相同为一类型的一组一只编号且长度固定的数据项的序列,这种类型可以是任意的原始类型,例如整型、字符串型或自定义类型。
例如,我要声明一个十个整数的数组
var array[10] int
数组的索引也是从0开始的
var name[size] type
var 名称[大小] 类型
例如:
var numbers[6] int
在经过初始化的数组中,{}中的元素的个数不能大于[]中的数字。默认情况下,不设置数组的大小,可以使用[…]代替,go语言会根据数组的个数来设置数组的大小
案例如下
var numbers = [6] int {1, 3, 5, 7, 9, 10}
var numbers = [...] int {1, 3, 5, 7, 9, 10}
数组元素可以通过索引的方法来读取,例如在声明了一个数组后,声明一个新的变量来通过数组索引的值来对其进行赋值,即可读取
var arr = [6] int {1, 3, 5, 7, 9, 10}
var ber int = arr[2]
示例代码:
package main
import (
"fmt"
)
func main() {
var arr [6]int
var i, j int
for i = 0; i < 6; i++ {
arr[i] = i + 1
}
for j = 0; j < 6; j++ {
fmt.Printf("array[%d] = %d\n", j, arr[j])
}
}
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。结构体是由0或多个任意类型的值聚合成的实体,每个值都可以称为“结构体的成员”
结构体的成员也可以被称为“字段”,这些字段有以下特性:
1.字段必须有自己的类型和值
2.字段名必须唯一
3.字段的类型也可以是结构体,甚至是字段所在结构体的类型
关键字type,可以将各种基本类型定义为自定义类型。基本类型包括整型、字符串、布尔等。结构体是一种复合的基本类型,通过type定义自定义类型,可以使结构体更便于使用
结构体的定义结构如下:
type 类型名称 struct {
字段 类型
字段2 类型
}
类型名称:表示自定义结构体的名称,同一个包内不能包含重复的类型名称
struct{} :表示结构体类型,type类型名struct{}可以被理解为将struct{}结构定义为类型名的类型
字段:表示结构体字段名,在结构体里字段名必须是唯一的
类型:表示结构体内字段的类型
例如:定义一个结构体来表示一个包含A和B的整型的结构
type numbers struct {
A int
B int
}
相同类型的变量可以写在同一行
type numbers struct {
A, B int
}
定义了结构体类型,他就可以用于变量的声明
variable_name := struct_variable_type {value1, value2, ...}
或
variable_name := struct_variable_type {key1 : value1, key2 : value2, ...}
定义一个地区的结构体,并打印
package main
import (
"fmt"
)
type address struct { //声明一个家庭地址结构体
province string //省
city_proper string //市
area string //区
street string //街道
}
func main() {
fmt.Println(address{"辽宁省", "沈阳市", "铁西区", "东北大马路"}) //简写,会依次将参数传入,缺点就是为空参数需要进行占位
fmt.Println(address{"辽宁省", "沈阳市", "铁西区", ""}) //此时可以发现,街道地址为空,需要进行占位
fmt.Println(address{province: "辽宁省", city_proper: "沈阳市"}) //若是使用key-value方式进行传参,可以将为空参数省略
}
如果要访问结构体成员,则需要适用英文点好“.”操作符,格式如下
结构体.成员名
package main
import (
"fmt"
)
type address struct { //声明一个家庭地址结构体
province string //省
city_proper string //市
area string //区
street string //街道
}
func main() {
var bear address //声明 bear 为 address 类型
var LiuMang address //声明 LiuMang 为 address 类型
//bear描述
bear.province = "江苏省"
bear.city_proper = "上饶市"
bear.area = "某区"
bear.street = "幸福大街"
//LiuMang描述
LiuMang.province = "四川省"
LiuMang.city_proper = "成都市"
LiuMang.area = "某区"
LiuMang.street = "甲子大街"
//打印bear信息
fmt.Printf("bear.province : %s\n", bear.province)
fmt.Printf("bear.city_proper : %s\n", bear.city_proper)
fmt.Printf("bear.area : %s\n", bear.area)
fmt.Printf("bear.street : %s\n", bear.street)
//打印LiuMang信息
fmt.Printf("LiuMang.province : %s\n", LiuMang.province)
fmt.Printf("LiuMang.city_proper : %s\n", LiuMang.city_proper)
fmt.Printf("LiuMang.area : %s\n", LiuMang.area)
fmt.Printf("LiuMang.street : %s\n", LiuMang.street)
}
可以像其他数据类型那样将结构体类型作为参数传递给函数
// arr.go
package main
import (
"fmt"
)
type address struct { //声明一个家庭地址结构体
province string //省
city_proper string //市
area string //区
street string //街道
}
func main() {
var bear address //声明 bear 为 address 类型
var LiuMang address //声明 LiuMang 为 address 类型
//bear描述
bear.province = "江苏省"
bear.city_proper = "上饶市"
bear.area = "某区"
bear.street = "幸福大街"
//LiuMang描述
LiuMang.province = "四川省"
LiuMang.city_proper = "成都市"
LiuMang.area = "某区"
LiuMang.street = "甲子大街"
printaddress(bear) //打印bear信息
printaddress(LiuMang) //打印LiuMang信息
}
func printaddress(add address) {
fmt.Printf("province : %s\n", add.province)
fmt.Printf("city_proper : %s\n", add.city_proper)
fmt.Printf("area : %s\n", add.area)
fmt.Printf("street : %s\n", add.street)
}
定义指向结构体的指针,类似于定义其他指针变量
var structNumber * address
以上定义的指针变量可以存储结构体变量的内存地址
如果要查看结构体变量的内存地址,则可以将&符号放置于结构体变量前
structNumber = &address
如果要使用结构体指针访问结构体成员,则使用“.”操作符
structNumber .title
// arr.go
package main
import (
"fmt"
)
type address struct { //声明一个家庭地址结构体
province string //省
city_proper string //市
area string //区
street string //街道
}
func main() {
var bear address //声明 bear 为 address 类型
var LiuMang address //声明 LiuMang 为 address 类型
//bear描述
bear.province = "江苏省"
bear.city_proper = "上饶市"
bear.area = "某区"
bear.street = "幸福大街"
//LiuMang描述
LiuMang.province = "四川省"
LiuMang.city_proper = "成都市"
LiuMang.area = "某区"
LiuMang.street = "甲子大街"
printaddress(&bear) //打印bear信息
printaddress(&LiuMang) //打印LiuMang信息
}
func printaddress(add *address) {
fmt.Printf("province : %s\n", add.province)
fmt.Printf("city_proper : %s\n", add.city_proper)
fmt.Printf("area : %s\n", add.area)
fmt.Printf("street : %s\n", add.street)
}
切片(slice)是对数组的一个连续“片段”的引用,所以切片是一个引用类型。
切片的内部结构包括内存地址、大小和容量
切片默认指向一段连续内存区域,可以是数组,也可以是切片本身。从连续内存区域生成切片是常见的操作,格式如下
slice [ 开始位置 : 结束位置]
slice:目标切片对象
开始位置:对应目标切片对象的开始索引
结束位置:对应目标切片的结束索引
从数组生成切片,代码如下
package main
import (
"fmt"
)
func main() {
var arr = [5]int{1, 2, 3, 4, 5} //生成一个1-5的整型数组
fmt.Println(arr, arr[1:2]) //arr[1:2]是一个切片,结果为[2]
}
从数组或切片生成新的切片拥有以下特性:
1.取出元素的数量为 “结束位置”减去“开始位置”
2.取出元素不包含结束位置对应的索引,切片最后一个元素使用slice[len(slice)]获取。
3.如果缺省开始位置,则表示连续区域开头到结束位置
4.如果缺省结束位置,则表示从开始位置到整个连续区域末尾
5.如果两边同时缺省,则新生成的切片与原切片等效
6.如果二者同时为0,则等效于空切片,一般用于切片复位
在根据索引位置去切片元素时,取值范围是(0-len(slice)-1), 如果超界就会报错。在生成切片时,结束位置可以填写(len(slice)),不会报错
案例如下
// var.go
package main
import (
"fmt"
)
func main() {
var arr [20]int
for a := 0; a < 20; a++ {
arr[a] = a
//fmt.Println(arr[a])
}
fmt.Println(arr[5:10]) //区间元素
fmt.Println(arr[:10]) //缺省开始
fmt.Println(arr[5:]) //缺省结尾
fmt.Println(arr[:]) //开始/末尾都缺省
fmt.Println(arr[0:0]) //复位切片
}
切片是动态结构,只能与nil判定相等,不能判定互等。在声明了新的切片后,可以使用append()函数向切片内添加函数。如果需要创建一个指定长度的切片,则可以使用make()函数,格式如下
make( []type, size, cap)
type是切片的元素类型
size是指这个类型分配了多少个元素
cap是指预分配的元素数量,这个值不影响size,只是提前预分配
package main
import (
"fmt"
)
func main() {
a := make([]int, 6)
b := make([]int, 6, 10)
fmt.Println(a, b)
fmt.Println(len(a), len(b))
}
go语言中map是一种特殊的数据类型,一种“元素对”(pair)的无序集合。
元素对包含一个key和一个value,所以这个结构也被称为“关联数组”或“字典”
map是引用类型,可以使用如下方法声明:
var name map [key_type] value_type
其中,name为map的变量名,key_type为键(key)类型,value_type为键对应的值类型。在key_type于value_type之间允许有空格
在声明时,不需要知道map的长度,因为map是可以动态增长的。未初始化的map值是nil,使用函数len()可以获取map中元素对的数目
// var.go
package main
import (
"fmt"
)
func main() {
var AMap map[string]string
var BMap map[string]string
AMap = map[string]string{"first": "走回家", "second": "跑回家"} //初始化map
CMap := make(map[string]int) //等价于 CMap := map [string] int{}
BMap = AMap //BMap是AMap的引用,修改BMap也会影响AMap
CMap["M1"] = 3
CMap["M2"] = 2
BMap["second"] = "打车回家"
fmt.Printf("第一种回家方式是: %s\n", AMap["first"])
fmt.Printf("第一种回家方需要花费: %d\n", CMap["M1"])
fmt.Printf("第二种回家方式是: %s\n", AMap["second"])
fmt.Printf("第三种回家方式是: %s\n", AMap["third"])
}
和数组不同,map可以根据新增的元素来动态伸缩,因此它不存在长度限制。但是为了性能考虑,可以使用初始化容量 capacity,格式如下
make (map [key_value] value_value, cap)
map := make(map [int] int, 100)
当map增长到预容量上限时,如果再增加新元素对,则map大小会自动增加1
用切片作为map值
既然一个key只能对应一个value,而key又是一个原始类型,那么如果一个key对应多个值呢?
通过将value定义为 []int 类型或其他类型的切片,就可以解决
map1 := make(map [int] [] int)
map2 := make(map [int] * [] int)