Golang基础
不求外物,不惧内心,不避因果
1. 简述
1.1 背景
-
Go语言自己的早期源码使用C语言和汇编语言写成
-
Go的三个作者分别是:Rob Pike(罗伯.派克),Ken Thompson(肯.汤普森)和Robert Griesemer(罗伯特.格利茨默)
-
2009年11月 GO语言第一个版本发布。2012年3月 第一个正式版本Go1.0发布
-
到go1.8时,相同业务场景下的GC时延已经可以从go1.1的数秒,控制在1ms以内。GC问题的解决,可以说GO语言在服务端开发方面,几乎抹平了所有的弱点
-
一家叫做 Docker 的公司。就是使用 Go 进行项目开发,并促进了计算机领域的容器行业,进而出现了像 Kubernetes 这样的项目
1.2 定义
将简单、实用体现得淋漓尽致的一种编程语言
1.3 GO项目
Docker 是一种操作系统层面的虚拟化技术,可以在操作系统和应用程序之间进行隔离,也可以称之为容器。Docker 可以在一台物理服务器上快速运行一个或多个实例。例如,启动一个 CentOS 操作系统,并在其内部命令行执行指令后结束,整个过程就像自己在操作系统一样高效。
Go语言自己的早期源码使用C语言和汇编语言写成。从 Go 1.5 版本后,完全使用Go语言自身进行编写。Go语言的源码对了解Go语言的底层调度有极大的参考意义,建议希望对Go语言有深入了解的读者读一读。
Google 公司开发的构建于 Docker 之上的容器调度服务,用户可以通过 Kubernetes 集群进行云端容器集群管理。系统会自动选取合适的工作节点来执行具体的容器集群调度处理工作。其核心概念是 Container Pod(容器仓)
一款分布式、可靠的 KV 存储系统,可以快速进行云配置。由 CoreOS 开发并维护键值存储系统,它使用Go语言编写,并通过 Raft 一致性算法处理日志复制以保证强一致性
beego 是一个类似 Python 的 Tornado 框架,采用了 RESTFul 的设计思路,使用Go语言编写的一个极轻量级、高可伸缩性和高性能的 Web 应用框架
一款快速构建模块化的 Web 应用的Go语言框架
国产的优秀分布式 Redis 解决方案。可以将 codis 理解成为 Web 服务领域的 Nginx,它实现了对 Redis 的反向代理和负载均衡。
Go语言强大的调试器,被很多集成环境和编辑器整合。
1.4 用处
- 区块链
- 云平台
- 嵌入式
- 网络编程
- 服务器编程
1.5 编程库
Go语言标准库包名 | 功 能 |
---|---|
bufio | 带缓冲的 I/O 操作 |
bytes | 实现字节操作 |
container | 封装堆、列表和环形列表等容器 |
crypto | 加密算法 |
database | 数据库驱动和接口 |
debug | 各种调试文件格式访问及调试功能 |
encoding | 常见算法如 JSON、XML、Base64 等 |
flag | 命令行解析 |
fmt | 格式化操作 |
go | Go语言的词法、语法树、类型等。可通过这个包进行代码信息提取和修改 |
html | HTML 转义及模板系统 |
image | 常见图形格式的访问及生成 |
io | 实现 I/O 原始访问接口及访问封装 |
math | 数学库 |
net | 网络库,支持 Socket、HTTP、邮件、RPC、SMTP 等 |
os | 操作系统平台不依赖平台操作封装 |
path | 兼容各操作系统的路径操作实用函数 |
plugin | Go 1.7 加入的插件系统。支持将代码编译为插件,按需加载 |
reflect | 语言反射支持。可以动态获得代码中的类型信息,获取和修改变量的值 |
regexp | 正则表达式封装 |
runtime | 运行时接口 |
sort | 排序接口 |
strings | 字符串转换、解析及实用函数 |
time | 时间接口 |
text | 文本模板及 Token 词法器 |
2. 下载和环境
尽量使用压缩包安装方式,注意GoWorks工作目录下三个包 bin src pkg
2.1 下载go
# 安装目录
GOROOT D:\install\go
# 工作目录
GOPATH D:\GoWorks
# 运行go.exe目录
PATH %GOROOT%\bin
Path %GOPATH%\bin
- 进行检测是否成功
go env
go version
go build
-
开发工具:idea、vscode、Go Reviverevive、Goland
-
vscode需要安装go工具包,在工作/bin目录下,运行F5
程序名 | 程序用途 |
---|---|
dlv.exe | go 语言调试工具 |
gocode.exe | go语言代码检查,自动补全 |
godef.exe | go语言代码定义和引用的跳转 |
golint.exe | go语言代码规范检查 |
go-outline.exe | 用于在Go源文件中提取JSON形式声明的简单工具 |
gopkgs.exe | 快速列出可用包的工具 |
gorename.exe | 在Go源代码中执行标识符的精确类型安全重命名 |
goreturns.exe | 类似fmt和import的工具,使用零值填充Go返回语句以匹配func返回类型 |
go-symbols.exe | 从go源码树中提取JSON形式的包符号的工具 |
gotour.exe | go语言指南网页版 |
guru.exe | go语言源代码有关工具,如代码高亮等 |
3. Go基础
3.1 hello.go
在Go语言里,命名为main的包具有特殊的含义。Go语言的编译程序会试图把这种名字的包编译为二进制可执行文件。所有用Go语言编译的可执行程序都必须有一个名叫main的包,一个可执行程序 有且仅有一个 main包
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
go run hello.go
当编译器发现某个包的名字为main时,它一定也会发现名为main()的函数,否则不会创建可执行文件。main()函数是程序的入口,所以,如果没有这个函数,程序就没有办法开始执行。程序编译时,会使用声明main包的代码所在的目录的目录名作为二进制可执行文件的文件名。
3.2 Go注释
方便其他人理解代码
//我是单行注释
/*
我是多行注释
我是多行注释
我是多行注释
我是多行注释
*/
3.3 变量
能够指向内存地址的可以变化的值,Go语言是静态类型语言
- 变量的定义(声明)
- 格式
var [name变量名] [type变量类型]
- eg
var (
name string
age int
money float64
isLike bool
)
fmt.Println(name, age,money, isLike )
// 空格 0 0 false
/*
整形和浮点型变量的默认值为0和0.0
字符串变量的默认值为空字符串
布尔型变量默认为false
切片、函数、指针变量的默认为nil
*/
- 初始化
- 格式
//变量声明
[name变量名] = [value变量值]
- eg
name = "dd"
age = 12
money = 12.45
isLike = true
- 声明并初始化
由于使用了 := ,而不是赋值的 = ,因此推导声明写法的左值必须是没有被定义过的,若定义过,将会发生编译错误
- 格式
[name未声明变量名] := [value变量值]
- eg
name := "dd"
age := 12
money := 12.45
isLike := true
//值改变,内存地址不变
name = "tt"
//交换,int会去掉float64小数部分
age, money = int(money), float64(age)
fmt.Println(name, age, money, isLike)
fmt.Printf("%T,%T,%T,%T", name, age, money, isLike)
fmt.Printf("%p,%p,%p,%p", &name, &age, &money, &isLike)
/*
dd 12 12.45 true
string,int,float64,bool
0xc000050270,0xc000018098,0xc0000180b0,0xc0000180b8
*/
- 匿名变量
匿名变量的特点是一个下划线 “_”,但任何赋给这个标识符的值都将被抛弃,可以极大地增强代码的灵活性,匿名变量不占用内存空间,不会分配内存。
- 格式
_ := [func/value]
- eg
func test() (int, int) {
return 100, 200
}
func main() {
a,_ := test()
_,b := test()
fmt.println(a,b)
}
- 变量作用域
一个变量(常量、类型或函数)在程序中都有一定的作用范围,称之为作用域,遵循就近原则
- 局部变量
在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,函数的参数和返回值变量都属于局部变量
- 全局变量
在函数体外声明的变量称之为全局变量,只需要在一个源文件中定义,就可以在所有源文件中使用,当然,不包含这个全局变量的源文件需要使用 import 关键字 引入
全局变量必须以 var 关键字开头,如果想要在外部包中使用全局变量的首字母必须大写
- 注意
Go语言程序中全局变量与局部变量名称可以相同,但是函数体内的局部变量会被优先考虑!
3.4 常量
是一个简单值得标识符,在程序运行时,不会被修改的量
- 普通常量
- 格式
const [name常量名] [type] = [value]
- eg
const url string = "ssss.xx"
const t, b, c = "s", 3.12, true
fmt.Println(t, b, c)
- 特殊常量iota
未赋值的常量向前面的常量寻找
- 格式
const [name常量名] [type] = iota
- eg
const (
a = iota //iota==0
b //iota==1
c //iota==2
d = "kuangshen" //iota==3
e = iota //iota==4
f = 100 //iota==5
g //iota==6
h = iota //iota==7
)
3.5 数据类型
- 布尔型
var isFlang bool //默认false
- 数字型
- 整数型
var age int//默认0
序号 | 类型和描述 |
---|---|
1 | uint8无符号8位整型(O到255) |
2 | uint16无符号16位整型(O到65535) |
3 | uint32无符号32位整型(O到4294967295) |
4 | uint64无符号64位整型(0到18446744073709551615) |
5 | int8有符号8位整型(-128到127) |
6 | int16有符号16位整型(-32768到32767) |
7 | int32有符号32位整型(-2147483648到2147483647) |
8 | int64有符号64位整型(-9223372036854775808到 9223372036854775807) |
- 浮点型
float32 不要进行运算,会精度损失
var money float64
fmt.Printf("%.3f", money)//这里打印浮点数类型为%.3f四舍五入,默认是6位小数打印
序号 | 类型和描述 |
---|---|
1 | float32 IEEE-754 32位浮点型数 |
2 | float64 lEEE-75464位浮点型数 |
3 | complex64 32位实数和虚数 |
4 | complex128 64位实数和虚数 |
- 其他别名
序号 | 类型和描述 |
---|---|
1 | byte类似于uint8 |
2 | rune类似于int32 |
3 | uInt32或64位 |
4 | int与uint一样大小 |
5 | uintprt无符号整形,用于存放一个指针 |
- 字符
单引号
//英文编码表 ASCII字符表
//汉字编码表 :GBK
//全世界编码表:Unicode
v1 := '在'
fmt.Printf("%T,%d", v1, v1)
//int32,22312
- 字符串
双引号
v2 := "在"
fmt.Printf("%T,%s", v2, v2)
//string,在
- 字符串连接和转义
fmt.Printf("%T,%s", v2, v2+"gg\"ff")
3.6 数据类型转换
数据类型转换都为显示,Go语言不存在隐式类型转换,每个分配的内存不同,bool类型和整数类型不能相互转换
c := float64(a)
3.7 运算符
- 算术运算符
运算符 | 描述 | 实例 |
---|---|---|
+ | 相加 | A+B输出结果30 |
- | 相减 | A-B输出结果-10 |
* | 相乘 | A*B输出结果为200 |
/ | 相除 | B/A输出结果为2 |
% | 求余 | B%A输出结果为0 |
++ | 自增 | A++输出结果11 |
– | 自减 | A–输出结果为9 |
v1 := 10
v2 := 3
fmt.Println(v1 / v2)
fmt.Println(v1 % v2)
- 关系运算符
运算符 | 描述 | 实例 |
---|---|---|
== | 检查两个值是否相等,如果相等返回True否则返回false | A==B 为false |
!= | 检查两个值是否不相等,如果不相等返回True否则返回false | A!=B为true |
> | 检查左边值是否大于右边值,如果是返回True否则返回false | A>B 为false |
< | 检查左边值是否小于右边值,如果是返回True否则返回false | A<B为True |
>= | 检查左边值是否大于等于右边值,如果是返回True否则返回false | A>=B 为false |
<= | 检查左边值是否小于等于右边值,如果是返回True否则返回false | A<=B 为true |
- 逻辑运算符
运算符 | 描述 | 实例 |
---|---|---|
&& | 逻辑AND运算符,如果两边的操作数都是True,则条件True,否则为False。 | A&&B 为false |
|| | 逻辑OR运算符,如果两边的操作数有一个True,则条件True,否则为False。 | A||B为true |
! | 逻辑NOT运算符,如果条件为True,则逻辑NOT条件False,否则为True。 | !(A&&B )为true |
- 位运算符
加密、解密、底层
运算符 | 描述 | 实例 |
---|---|---|
& | 按位与运算符"&"是双目运算符。都是1结果为1,否则是0 | (A&B)结果为12,二进制为0000 1100 |
| | 按位或运算符"|"是双目运算符。只要有一个1就为1,都是0结果为0,否则是1 | (A |B)结果为61,二进制0011 1101 |
^ | 按位异或运算符"A"是双目运算符。不同则为1,相同为0 | (A^B)结果为49,二进制为0011 0001 |
&^ | 位清空,a &^b,对于b上的每个数值,如果为0,则取a对应位上的数值,如果为1,则取0. | (A&^B)结果为48,二进制为0011 0000 |
<< | 左移运算符"<<“是双目运算符。左移n位就是乘以2的n次方。其功能把”<<“左边的运算数的各二进位全部左移若干位,由”<<"右边的数指定移动的位数,高位丢弃,低位补O。 | A<<2结果为240,二进制为1111 0000 |
>> | 右移运算符">>“是双目运算符。右移n位就是除以2的n次方。其功能是把”>>“左边的运算数的各二进位全部右移若干位,”>>"右边的数指定移动的位数。 | A>>2结果为15,二进制为0000 1111 |
v1 := 10
v2 := 3
fmt.Printf("%b\n", v1)
fmt.Printf("%b\n", v2)
v3 := v1 & v2
fmt.Printf("%b\n", v3)
v4 := v1 | v2
fmt.Printf("%b\n", v4)
v5 := v1 ^ v2
fmt.Printf("%b\n", v5)
v6 := v1 << 2
fmt.Printf("%b\n", v6)
v7 := v2 >> 2
fmt.Printf("%b\n", v7)
1010
11
10
1011
1001
101000
0
- 赋值运算符
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符,将一个表达式的值赋给一个左值 | C =A+B将A+B表达式结果赋值给C |
+= | 相加后再赋值 | C +=A等于C=C+A |
-= | 相减后再赋值 | C -=A等于C=C-A |
*= | 相乘后再赋值 | C *=A等于C=C *A |
/= | 相除后再赋值 | C/=A等于C=C/ A |
%= | 求余后再赋值 | C%=A等于C=C%A |
<<= | 左移后赋值 | C<<=2等于C=C<<2 |
>>= | 右移后赋值 | C>>=2等于C=c>>2 |
&= | 按位与后赋值 | C&=2等于C=C&2 |
^= | 按位异或后赋值 | C=2等于C=C2 |
!= | 按位或后赋值 | C|=2等于C=C|=2 |
- 其他运算符
运算符 | 描述 | 实例 |
---|---|---|
& | 返回变量存储地址 | &a;将给出变量的实际地址 |
* | 指针变量 | *a;是一个指针变量 |
3.8 输入输出
var x int
var y float64
//Print
//Printf 格式化
//Println 换行
fmt.Println("请输入")
fmt.Scanln(&x, &y)
fmt.Println(x, y)
3.9 编码规范
-
当命名(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的public) ;
-
命名如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的private )
-
保持package的名字和目录名保持一致,尽量采取有意义的包名,简短,有意义,尽量和标准库不要冲突。包名应该为小写单词,不要使用下划线或者混合大小写。
-
尽量