Go语言学习笔记(3)

数组

Golang 中,数组是值类型。

数组的声明

var arr [10]int

数组的初始化

var arr1 [3]int = [3]int{1, 2, 3}
var arr2 = [3]int{4, 5, 6}
var arr3 = [...]int{7, 8, 9}
var arr4 = [...]int{1: 100, 2: 200, 3: 300}

用 for-range 遍历数组

基本语法:

for index, value := range 数组变量{
}

其中:index 为数组下标,value 是该下标位置的值。

长度是数组类型的一部分

长度是数组类型的一部分,就是说数组不可以脱离长度而存在。听起来不太明白,我们来看下面的一个示例就明白了,这真的是一个大坑。

假设,我们现在要写一个排序函数,C# 中,我们会这样定义:

public void Sort(int[] array)
{
}

但是,在 Golang 中,这是不行的。

func main() {
    var arr [3]int = [3]int{1, 2, 3}
    Sort(arr)
}

func Sort(array []int){
}

Sort(arr) 这句编译就会报错:cannot use arr (type [3]int) as type []int in argument to Sort。因为 Sort 函数的参数 array []int 是一个切片,不是数组,将数组作为参数传给 Sort 就会报类型不匹配。

如果一定需要以数组作为参数传递,Sort 的参数必须定义成数组,就是带上长度:

func Sort(array [3]int){
}

这么定义这函数还有啥用?吐槽一万字...
虽然有切片可以用来实现我们的功能,但是,数组就变得有点鸡肋了。

切片 slice

切片是引用类型,类似于 C# 中的 list 。内部维护一个数组,当追加元素超出切片容量时,切片自动扩容。(跟 list 是一样的机制。)

切片的声明

var arr []int

切片的使用

//方法一:
var arr1 [5]int = [5]int{1, 2, 3, 4, 5}
slice1 := arr1[1: 3]    //这里的使用跟 Python 很像

//方法二:
var slice2 []int = make([]int, 5, 10)

//方法三:
var slice3 []int = []int{1, 2, 3, 4, 5}

使用 make 初始化切片,make 的三个参数依次为:切片数据类型,切片长度,切片容量。

给切片追加元素

//方法一:追加一个或多个同类型
var slice1 []int = make([]int, 5, 10)
slice1 = append(slice1, 100, 200)
fmt.Printf("%v\n", slice1)

//方法二:追加切片(只能是切片,不可以是数组)
var slice2 []int = []int{1, 2, 3, 4, 5}
slice1 = append(slice1, slice2...)    // 三个点不能少
fmt.Printf("%v", slice1)

append 函数也很搞笑,其返回值必须赋值给一个切片,否则编译都过不了。如果一个切片调用 append 追加元素后,又赋值给了自己(我们一般也是这么用的),则切片的地址不会发生改变(除非发生了扩容)。如果 切片 1 调用 append 后赋值给了 切片 2,则 切片 1 保持未追加前的原样不变,另生成一个新的切片赋给 切片 2

示例:

var slice1 []int = make([]int, 5, 10)
fmt.Printf("%v %p\n", slice1, &slice1)  // [0 0 0 0 0] 0xc000004460

slice1 = append(slice1, 100)
fmt.Printf("%v %p\n", slice1, &slice1)  // [0 0 0 0 0 100] 0xc000004460
    
slice2 := append(slice1, 200)
fmt.Printf("%v %p\n", slice1, &slice1)  // [0 0 0 0 0 100] 0xc000004460
fmt.Printf("%v %p\n", slice2, &slice2)  // [0 0 0 0 0 100 200] 0xc0000044e0

映射 map

就是字典。

map 的声明

var m map[int]string

map 的使用

// 方式一:使用 make 函数
m := make(map[int]string, 10)

// 方式二:直接赋值
m := map[int]string{
    1: "张三",
    2: "李四",
}

make 方法的第一个参数是 map 的数据类型,第二个参数是初始容量。

注意,如果是方式二直接赋值,最后一个 key-value 后面也要加逗号。

删除元素

delete(map, key)

参数:

  • map:要删除元素的 map
  • key:要删除的 key,当 key 在 map 中不存在时,不进行任何操作,也不报错。

Golang 中 map 没有类似其他语言中的 clear 方法,如果要一次性删除全部元素,可遍历 map 逐一删除,或者重新 make 一下使其指向一个新的内存空间。

查找元素

val, finded := m[1]
if finded{
    fmt.Println(val)
}

遍历元素

只能用 for-range 遍历

for k, v := range m{
    fmt.Printf("%v: %v\n", k, v)
}

结构体 struct

  • Golang 中没有类(class),Go 中的结构体(struct)和其他语言中的类有同等的地位。可以理解为 Golang 是基于 struct 来实现面向对象。
  • Golang 中面向对象编程非常简洁,去掉了传统 OOP 语言中的继承、方法重载、构造函数、析构函数、隐藏的 this 指针等等。
  • Golang 仍然有面向对象编程的封装、继承、多态的特性,只是实现方式和其他 OOP 语言不一样。
  • 结构体是值类型。结构体的所有字段在内存中是连续的。

结构体的声明

type 结构体名称 struct{
    field1 type
    field2 type
}

结构体的使用

type Person struct{
    Name string
    Age int
}

// 方式一:
p1 := Person{}
p1.Name = "Tom"
p1.Age = 10

// 方式二:
p2 := Person{"Jerry", 5}

// 方式三:
p3 := Person{Name: "张三", Age: 30}
// 或:
p3 := Person{
    Name: "张三", 
    Age: 30,                // 注意这里要加逗号,否则会被默认加上分号
}

结构体指针

// 方式一:
var person1 *Person = new(Person)
(*person1).Name = "Tom"
(*person1).Age = 10
fmt.Println(*person1)

// 方式二:
person2 := new(Person)
person2.Name = "Tom"
person2.Age = 10
fmt.Println(*person2)

// 方式三:
var person3 *Person = &Person{"Jerry", 5}
fmt.Println(*person3)

这三种方式定义的都是结构体指针,因为是指针,所以给字段赋值的标准方式应该是方式一的写法,但是 Go 的设计者为了程序员使用方便,给出了一个语法糖,使 (*person1).Name = "Tom" 简化为 person1.Name = "Tom",即方式二的写法,编译时,会自动加上取值运算。而方式三的写法可以直接赋值。

结构体标签

struct 的每个字段上可以定义一个标签(tag),该标签可以通过反射机制获取,最常见的使用场景就是序列化和反序列化。

type Person struct{
    Name string `json:"name"`
    Age int `json:"age"`
}

p := Person{"张三", 30}
jsonStr, err := json.Marshal(p)
if err == nil {
    fmt.Println(string(jsonStr)) // {"name":"张三","age":30}
}

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

推荐阅读更多精彩内容