定义struct出错指针不允许指向不完整类型_Go入门系列(三)复合数据类型

本文详细介绍了Go语言中的指针、数组、结构体以及切片、Map和迭代的概念。通过实例演示了如何操作这些数据类型,包括指针的使用、数组和结构体的定义、动态数组切片的灵活性,以及Map的键值对操作和迭代方法。
摘要由CSDN通过智能技术生成

baaba6967d9103bba9bfdd8e2dbecc8b.gif

目录:
一、指针类型(Pointer)
二、数组类型
三、结构化类型(struct)
四、 切片类型
五、Map 类型
六、迭代

一、指针类型(Pointer)

Go语言指针类似C/C++,区别在于它不支持指针运算。&为取地址符&,放到一个变量前使用就会返回相应变量的内存地址。
一个指针变量可以指向任何一个值的内存地址,它所指向的值的内存地址在 32 和 64 位机器上分别占用 4 或 8 个字节,占用字节的大小与所指向的值的大小无关。当一个指针被定义后没有分配到任何变量时,它的默认值为 nil。指针变量通常缩写为 ptr。

func main() {
a:=1
ptr:=&a //等价var ptr *int=&a
fmt.Println(ptr)
fmt.Println(*ptr)
}
#输出
0xc00000a0b8
1

指针最基本的操作就是对地址直接访问(读/写):

func main() {
a:=1
ptr:=&a //等价var ptr *int=&a
fmt.Println(ptr)
*ptr=2
fmt.Println(a)
}
#输出
0xc00000a0b8
2

介绍到这里似乎开始疑惑为什么总有人对指针谈虎色变呢?因为指针一旦结合函数、数组、切片、闭包等投入到实例应用时,越界、野指针、偏移等等各种问题便产生了,作为入门系列不在此展开。

二、数组类型

数组是具有相同唯一类型的一组已编号且长度固定的数据项序列。
格式规则为:var variable_name [SIZE] variable_type

func main() {
var user [10] string
user[0]="rabbit"
fmt.Print(user)
}
#输出
[rabbit ]

或者可不设置size直接进行初始化,Go 语言会根据元素的个数来设置数组的大小:

func main() {
var user =[] string{"rabbit","carrot"}
fmt.Print(user)
}
#输出
[rabbit carrot]

当然可以像其它基本类型一样继续偷懒:

func main() {
user:=[] string{"rabbit","carrot"}
fmt.Print(user)
}

三、结构化类型(struct)

即结构体,结构体是由一系列具有相同类型或不同类型的数据构成的数据集合,结构体定义需要使用 type 和 struct 语句,格式规则样例如下,相对于数组可以存储同一类型的数据,结构体可以为不同项定义不同的数据类型。:

type People struct {
name string
age int
city string
}

基本访问方式:

func main() {
type User struct {
name string
age int
city string
}
user :=User{name:"rabbit",age:18}
fmt.Print(user.name)
}
#输出
rabbit

同样,我们可以结合刚刚提到的指针,将指针结合到结构体变量中:

func main() {
type User struct {
name string
age int
city string
}

user :=User{name:"rabbit",age:18}
ptr:=&user
fmt.Print(ptr.name)
}
#输出
rabbit

此外,你可以像其他数据类型一样将结构体类型作为参数传递给函数。并以以上实例的方式访问结构体变量,这个我们在下一章的函数章节会提到。

四、切片类型

切片是对数组的抽象,Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
我们可以直接对数组进行截取,len()cap()分别可测量长度和测量切片最长可以达到多少。

func main() {
arr:=[]int{1,2,3,4,5}
s:=arr[0:3]
fmt.Println(arr)
fmt.Println(s)
fmt.Println(len(s),cap(s))
}

我们也可以通过内置的make()方法声明一个切片,其规则为:

s :=make([]int,len,cap) 

初始化为空切片,实际长度初始化后重新动态校正:

func main() {
arr:=[]int{1,2,3,4,5}
s:=make([]int,0,5)
fmt.Println(len(s),cap(s),s)
s=arr[3:5]
fmt.Println(len(s),cap(s),s)
}
#输出
0 5 []
2 2 [4 5]

make()方法中的cap参数可以省略,此外切片提供了copy()方法和append()方法,用以拷贝切片和增加新元素。

func main() {
arr:=[]int{1,2,3,4,5}
s:=arr[0:3]
s1:=make([]int,10)
fmt.Println(len(s),cap(s),s)
copy(s1,s)
fmt.Println(len(s1),cap(s1),s1)
s1=append(s,6,7,8)
fmt.Println(len(s1),cap(s1),s1)
}
#输出
3 5 [1 2 3]
10 10 [1 2 3 0 0 0 0 0 0 0]
6 10 [1 2 3 6 7 8]

其中copy()方法有个需要注意的地方,如果s1声明的长度为0,你会发现s1并未copy成功,因为copy()不会新建新的内存空间,由它原来的切片长度决定。

五、 Map 类型

Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。
如果你有python基础,我说字典类型你可能会立刻明白,yes,就是它。
map声明方式有两种,其格式规则为:

/* 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type

/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)

需要注意的是,使用前者需要初始化,我们尝试下基本使用。

func main() {
user:=make(map[string]int)
user["rabbit"]=18
user["carrot"]=17

fmt.Print(user,user["rabbit"])
}
#输出
map[carrot:17 rabbit:18] 18

或者使用前者并借助make初始化:

func main() {
var user map[string]int
user=make(map[string]int)
user["rabbit"]=18
user["carrot"]=17

fmt.Print(user,user["rabbit"])
}

此外,在切片小节我们提到了,make()方法是有一个可省略的容量属性的,我们上述代码同样选择了忽略,但请留意它的存在,如下使用也是允许的。

user=make(map[string]int,100)

此外,map支持delete()方法:

func main() {
var user map[string]int
user=make(map[string]int,100)
user["rabbit"]=18
user["carrot"]=17
fmt.Println(user)
delete(user,"carrot")
fmt.Println(user)
}
#输出
map[carrot:17 rabbit:18]
map[rabbit:18]

六、迭代

当然,迭代并不算数据类型,放在本节最后讨论下复合数据类型的迭代方式,主要借助range方法。
首先遍历我们刚看完的map类型:

func main() {
user:=make(map[string]int,100)
user["rabbit"]=18
user["carrot"]=17
for k,v :=range user{
fmt.Printf("%s - > %d\n",k,v)
}
}
#输出
carrot - > 17
rabbit - > 18

然后尝试下数组迭代:

func main() {
arr:=[]int{1,2,3,4,5}
for i,num:=range arr{
println(i,num)
}
}
#输出
0 1
1 2
2 3
3 4
4 5

可以看到相对于python区别还是比较大的,返回值为两个,索引和值。
在此暂时以这两个常用类型为例,后边根据进度补充。

c39e263272455bff7410dbbd06168473.png

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值