Go编程基础(array、slice、map和struct)

这篇讲解go语言中数据存储类型array、slice、map和struct,要清楚它们那些是值传递,那些是指针传递(也就是引用类型),这对后面的数据处理非常重要!

1.数组Array

定义数组的格式:

var <varName> [n]<type>
image.png

示例如下:

package main
import "fmt"
func main() {
    //先声明,后赋值
    var a [2] string
    a[0]="hello"
    a[1]="world"
    fmt.Println(a[0],a[1])
    fmt.Println(a)
    //声明并赋值
    prime:=[6]int{2,3,5,7,11,13}
    fmt.Println(prime)
}
image.png

数组需要注意的点:

  • 1、数组长度也是类型的一部分,因此具有不同长度的数组为不同类型;
  • 2、注意区分指向数组的指针和指针数组;
  • 3、数组在Go中为值类型;(这是和Java非常不同的一点)
  • 4、数组之间可以使用==或者!=进行比较,但不可以使用<>
  • 5、可以使用new来创建数组,此方法返回一个指向数组的指针
  • 6、Go支持多维数组

区分指向数组的指针和指针数组

package main
import "fmt"
func main() {
    //可以利用...不指定数组长度
    a:=[...]int{9:1}
    //指向数组的指针
    var p *[10]int=&a
    fmt.Print(p)
}
image.png
package main
import "fmt"
func main() {
    x,y :=1,2
    //指针数组
    a:=[...]*int{&x,&y}
    fmt.Print(a)
}
image.png

2.切片slice(重点)

切片需要注意的点:

  • 1、其本身并不是数组,它指向底层的数组。(切片为引用类型)
  • 2、作为变长数组的替代方案,可以关联底层数组的局部或全部;
  • 3、可以直接创建或从底层数组获取生成;
  • 4、一般使用make()创建,使用len()获取元素个数,cap()获取容量;
  • 5、如果多个slice指向相同的底层数组,其中一个的值改变会影响全部。

Slice的第一种创建方式:

package main
import "fmt"
func main() {
    //创建一个切片,跟数组相比没有规定长度
    p:=[]int{2,3,5,7,11,13}
    fmt.Println("p==",p)
    for i := 0; i < len(p); i++ {
        fmt.Println(i,p[i])
    }
}

Slice的第二种创建方式:

package main
import "fmt"
func main() {
    //利用make创建包含3个元素,容量为10的slice
    //提前分配容量10是为了增加元素而在此分配内存
    s1:=make([]int,3,10)
    fmt.Println(len(s1),cap(s1))
    //注意打印出来的时候只包含三个元素
    fmt.Println(s1)
}
image.png

Slice与底层数组的对应关系:

image.png

Reslice的理解:

  • 1、Reslice时索引以被slice的切片为准;
  • 2、索引不可以超过被slice的切片的容量cap()值;
  • 3、索引越界不会导致底层数组的重新分配而引发错误。
package main
import "fmt"
func main() {
    a:=[]byte{'a','b','c','d','e','f','g','h','i','j','k'}
    //前闭后开
    sa:=a[2:5]
    //转化为字符串
    fmt.Println(string(sa))
    fmt.Println(len(sa),cap(sa))
    //从sa中取出元素--reslice功能
    sb:=sa[3:5]
    //打印出来的是fg,但是sa中并没有fg,这是为什么呢?
    //sa的本质是指针,指向的数组的地址,它会包含从3到最后一个元素的地址。(就像图中阴影部分的元素)
    fmt.Println(string(sb))
}
image.png

Append的理解:

  • 1、可以在slice尾部追加元素;
  • 2、可以将一个slice追加在另一个slice尾部;
  • 3、如果最终长度未超过追加到slice的容量则返回原始slice,如果超过追加到的slice的容量则将重新分配数组并拷贝原始数据。
package main
import "fmt"
func main() {
    s1:=make([]int,3,6)
    //按格式输出
    fmt.Printf("%p\n",s1)
    s1 =append(s1,1,2,3)
    fmt.Printf("%v %p\n",s1,s1)
    s1 =append(s1,1,2,3)
    fmt.Printf("%v %p\n",s1,s1)
}
image.png

3.map

map的基本定义:

  • 1、类似其它语言中哈希表或者字典,以key-value形式存储数据;
  • 2、Key必须是支持==!=比较运算的类型,不可以是函数、mapslice
  • 3、Map查找比线性搜索快很多,但比使用索引访问数据的类型慢100倍;
  • 4、Map使用make()创建,支持:=这种简写方式,make([keyType] valueType,cap)cap表示容量,可省略;超出容量时会自动扩容,但尽量提供一个合理的初始值;使用len()获取元素的个数。
  • 5、键值对不存在时自动添加,使用delete()删除某键值对,比如delete(m,1)
  • 6、使用for rangemapslice进行迭代操作。

map创建的方式一:

package main
import "fmt"
func main() {
    //声明一个map,int是key类型,string是value类型
    var m map[int]string
    //初始化map
    m =map[int]string{}
    fmt.Print(m)
}

map创建的方式二:

package main
import "fmt"
func main() {
    //使用make创建一个map
    m:=make(map[int]string)
    m[1]="OK"
    a:=m[1]
    fmt.Println(m)
    fmt.Print(a)
}
image.png

通过rangemap进行初始化操作如下:

package main
import "fmt"
func main() {
    //创建一个slice
    sm:=make([]map[int]string,5)
    //对一个slice进行迭代,并对slice中的map进行初始化(i对代表的索引下标,v是代表对应的值)
    for i:= range sm {
        //注意是通过索引去改变map中的值,否则只是普通的值拷贝
        sm[i] =make(map[int]string,1)
        sm[i][1] ="OK"
        fmt.Println(sm[i])
    }
    fmt.Println(sm)
}
image.png

使用map作为函数的参数传递:引用传递

package main
import "fmt"
func main() {
    a:=map[string]int{
        "Michaeljian":22,
        "Jerry":20,
    }
    mapTest(a)
    fmt.Print(a["Michaeljian"])
}
//将map作为参数传递进去并修改对应的值
func mapTest(b map[string]int) {
    b["Michaeljian"] = 18
}
image.png

4.struct

struct的知识要点:

  • 1、Go中的struct与C中的struct非常相似,并且Go没有class,使用type<Name>struct{} 定义结构,名称遵循可见性规则;
  • 2、支持指向自身的指针类型成员,支持匿名结构,可用作成员或定义成员变量,匿名结构也可以用于map值;
  • 3、可以使用字面值对结构进行初始化,允许直接通过指针来读写结构成员;
  • 4、相同类型的成员可进行直接拷贝赋值;
  • 5、支持==!=比较运算,但不支持><
  • 6、支持匿名字段,本质上是定义了以某种类型名为名称的字段;
  • 7、可以使用匿名字段指针;
  • 8、嵌入结构作为匿名字段看起来像继承,但不是继承。

struct的定义和赋值:

package main
import "fmt"
type person struct {
    Name string
    Age int
}
func main() {
    a:=person{}
    a.Name ="Michaeljian"
    a.Age =25
    fmt.Print(a)
}

使用struct作为函数传递的参数:值传递

package main
import "fmt"
type person struct {
    Name string
    Age int
}
func main() {
    //字面值初始化
    a:=person{
        Name:"Michaeljian",
        Age:25,
    }
    fmt.Println(a)
    A(a)
    fmt.Println(a)
}
func A(p person) {
    p.Age = 12
    fmt.Println("A",p)
}
image.png

如何想要将struct作为引用传递,需要借助指针:

package main
import "fmt"
type person struct {
    Name string
    Age int
}
func main() {
    //字面值初始化
    a:=person{
        Name:"Michaeljian",
        Age:25,
    }
    /**
    //一般在开发中会采用这种的方式,直接将person的地址赋值给a
        a:= &person{
        Name:"Michaeljian",
        Age:25,
    }
    //此时注意要修改Name的值话直接采用下面的方式即可。
    a.Name="Jerry"
    */
    fmt.Println(a)
    //传入struct的地址
    A(&a)
    fmt.Println(a)
}
func A(p *person) {
    p.Age = 12
    fmt.Println("A",p)
}
image.png

使用匿名结构类型声明struct,格式如下:

package main
import "fmt"
func main() {
  //可以a:=&struct{}{}做地址传递
    a:= struct {
        Name string
        Age int
    }{
        Name:"Michaeljian",
        Age:19,
    }
    fmt.Print(a)
}

使用struct的嵌入结构,格式如下:

package main
import "fmt"
type human struct {
    Sex int
}
type teacher struct {
    human
    Name string
    Age int
}
type student struct {
    human
    Name string
    Age int
}
func main() {
    //如何给嵌入结构human中的字段赋值,human:human{Sex:1}
    a:=teacher{Name:"Michaeljian",Age:25,human:human{Sex:1}}
    b:=student{Name:"Jerry",Age:24,human:human{Sex:2}}
    a.Name ="Jerry"
    a.Sex = 100
    fmt.Print(a,b)
}
image.png

参考资料

https://github.com/Unknwon/go-web-foundation

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

推荐阅读更多精彩内容