Go入门系列(三)复合数据类型

目录:
一、指针类型(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区别还是比较大的,返回值为两个,索引和值。
在此暂时以这两个常用类型为例,后边根据进度补充。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容