1. 开始学习Go
从一本书开始,这本书叫做《Go语言从入门到进阶实战(视频教学版)》,当然这篇Blog并不是所有的内容都来自这本书,毕竟书中也有不足之处。
2. Hello World
学啥语言的第一步都是Hello World, 第一步是搭建开发环境,直接下载Goland,创建一个新的工程,点击create
建好项目以后,项目应该是下面这个样子的,当然我们不用关注这个go.mod是干什么的,我们只是利用IDE编写代码,使用命令行运行。
1 | s@HELLOWANG-MB1 go-study % tree |
然后新建一个main.go的文件,其内容如下
1 | package main |
最后运行该文件
1 | s@HELLOWANG-MB1 go-study % go run main.go |
我们也可以编译为二进制文件,然后运行
1 | s@HELLOWANG-MB1 go-study % go build main.go |
3. Go的变量声明
变量的声明方式为var <变量名> <变量类型>
例如下面的程序
1 | package main |
经过了命令行运行以后,可以转而使用IDE集成开发,点击按钮▶️
当然,还有更多的声明方式
1 | package main |
最后还有一个小技巧,即函数返回可以是多个变量,用逗号分隔, _
表示匿名变量,即忽略该位置的值。
1 | package main |
4. Go 的基础数据类型
4.1. 整形
有符号整型: int8 int16 int32 int64
无符号整型: uint8 uint16 uint32 uint64
平台自适应整形: int uint
(自动根据平台决定整形的长度)
4.2. 浮点数
float32 float64
1 | package main |
4.3. 布尔型
1 | package main |
4.4. 字符串
1 | package main |
多行字符串
1 | package main |
5. Go的控制流
5.1. 循环
1 | package main |
5.2. 条件判断
1 | package main |
5.3. switch
需要注意的是Go的switch自带break,下面的程序只会输出3
1 | package main |
6. Go的容器/集合
6.1. Map
注意map需要指定key和value 的类型
1 | package main |
6.2. 数组
数组长度固定, 创建数组也有很多种写法
1 | package main |
注意对于由字面量组成的数组,如果长度小于等于4,那么它将直接被分配到栈上,否则分配到静态区
6.3. 切片
切片的创建可以是数组的一部分,也可以直接创建,切片可扩容
1 | package main |
那么切片和数组有什么区别呢?其实切片只是数组的一个引用,任何一个切片,其背后一定有一个数组,当切片进行扩容的时候,会根据数组的剩余空间大小来决定附身到新的数组上,或者直接在原数组上扩容切片。
具体表现如下, 输出就在注释里面。
1 | package main |
6.3. 列表
列表可以自动伸缩
1 | package main |
7. Go的函数
返回值写在参数后面
1 | package main |
还可以选择返回多个值
1 | package main |
变长的参数
1 | package main |
返回一个函数
1 | package main |
8. Go的指针
和C一样
9. Go 的结构体
9.1. 结构体定义
1 | type <类型名> struct { |
例子:
1 | type Point struct { |
9.2. 结构体实例化
1 | package main |
使用new实例化,注意此时得到的p2是指针
1 | package main |
9.3. 结构体函数
结构体函数定义比普通函数定义在func和函数名之间多了一个结构体对象,这个对象一般使用指针
1 | package main |
9.4. 结构体的Tag
结构体中的字段可以设置Tag,即给字段打上标签,就像Java中的注解一样。然后可以使用一种比较高级的技术(反射来获取这个标签)
1 | package main |
10. Go的接口
接口定义
1 | type <接口类型名> interface{ |
让结构体实现接口, 只需要让结构体的函数与接口保持一致即可,
1 | package main |
11. Go的包
回到最开始的Helloworld,注意到第一行中的package main
, 在Go中,有这样一个约定
包名为main的包为应用程序的入口包,编译源码没有main包时,将无法编译输出可执行的文件。
1 | package main |
11.1. Go的包导出
在Go中,首字母为小写的变量只能在包内使用,首字母为大写的变量会自动导出,可以在其他包使用。
这是第一个文件mylib/mylib.go
1 | package mylib |
11.2. Go的包导入
然后是main.go
, 注意到可以直接使用Add
函数,但是不能使用add
函数
1 | package main |
在导入的时候可以直接重命名,只需要在包名前加上一个名字即可
1 | package main |
11.3. Go的包的init函数
一个包的init函数在包被引入时自动调用, 对于main包,init函数在main函数前运行
1 | package mylib |
1 | package main |
12. Go的反射
12.1. Go反射类型
通过reflect包来进行反射,可以获得类型
1 | package main |
对于name和kind的区别,看看下面这份代码就行了, name为Point,kind为struct
1 | package main |
12.2. Go反射值
通过字段的名字获取属性
1 | package main |
13. Go的并发
13.1. goroutine
在关键词go后跟着一个函数调用,那么该函数调用就变成了goroutine,这是一个异步调用,立即返回
1 | package main |
13.2. Go的通道
下面的程序会依次输出0和hello
, 通道先进先出 <-
符号可以用来传输数据, 注意通道在发送和接受的时候都会阻塞,注意到最后一行有一个time.Sleep(time.Second)
,这是为了等待goroutine完成,否则main退出以后goroutine会直接强制退出
1 | package main |
另一种接受方法是使用for循环,代码如下,注意这个循环需要手动退出
1 | package main |
最后通道还支持指定输入端和输出端,输入端只能做输入,输出端只能做输出
1 | package main |
创建带有缓冲区的通道, 只需要在make的第二个参数中填入数字即可
1 | ch := make(chan interface{}, 10) |
多路复用,使用select关键字,case区域写要选择的通道即可接收多个通道,下面的代码有时输出1,有时输出2
1 | package main |
- 本文作者: fightinggg
- 本文链接: http://fightinggg.github.io/yilia/yilia/R0T00O.html
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!