Go 语言快速入门——基础语法
Go语言准备工作
1、Go安装
2、Go命令
go build
-
在项目目录下执行
go build
-
在其他路径下执行
go build
, 需要在后面加上项目的路径(项目路径从GOPATH/src后开始写起,编译之后的可执行文件就保存在当前目录下) -
go build -o hello.exe
go run
像执行脚本文件一样执行Go代码
go install
go install
分为两步:
-
先编译得到一个可执行文件
-
将可执行文件拷贝到
GOPATH/bin
交叉编译
Go支持跨平台编译
例如:在windows平台编译一个能在linux平台执行的可执行文件
1 | SET CGO_ENABLED=0 // 禁用CGO |
执行go build
Mac平台交叉编译:
1 | CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build |
3、GO语言文件基础语法
存放Go源代码的文件后缀名是.go
文件第一行:package
关键字声明包名
如果要编译可执行文件,必须要有main包和main函数(入口函数)
1 | // 单行注释 |
Go语言函数外的语句必须以关键字开头
函数内部定义的变量必须使用
基本语法
1、HelloWorld 程序
1 | package main |
2、变量与常量
- 标识符:字母与下划线开头
- 关键字(25个):
1 | break default func interface select |
- 保留字(37个):
1 | Constants: true false iota nil |
- 变量声明
1 | var 变量名 变量类型 (= 表达式) |
【特性】
- Go语言推荐使用驼峰命名法;
- Go语言中变量声明了必须使用;
- 函数外的每个语句都必须以关键字开始(var、const、func等);
:=
不能使用在函数外;_
多用于占位,表示忽略值;匿名变量不占用命名空间,不会分配内存,所以匿名变量之间不存在重复声明。
- 常量声明
1 | const pi = 3.1415 |
【特性】
- 常量在定义的时候必须赋值;
- 整型
1 | package main |
- 浮点型
1 | package main |
- 布尔型
1 | package main |
- fmt 占位符
1 | package main |
- 字符串
1 | // 字符串 |
【注意】
- 字符串必须用
""
包裹; - Go语言中
''
包裹的是字符!!!
- byte与rune类型
1 | package main |
3、字符串修改与类型转换
1 | package main |
4、if 判断与 for 循环
- if
1 | package main |
- for
1 | package main |
5、switch 与 goto
- switch:
1 | package main |
- goto:
1 | package main |
6、运算符
1 | package main |
7、数组(array)
1 | package main |
8、切片(slice)
定义:拥有相同类型元素的可变长度的序列。
实质:切片就是一个框,框住了一块连续的内存;切片属于引用类型,真正的数据都是保存在底层数组里的。
切片之间是不能比较的,我们不能使用==
操作符来判断两个切片是否含有相等的元素。
1 | package main |
【注意】
- 底层数组从切片的第一个元素到最后的元素数量
9、使用make()函数创造切片
1 | package main |
10、切片进阶
- append()方法为切片添加元素
1 | package main |
【注意】
- 切片的扩容策略:
- 如果申请的容量大于原来的2倍,那就直接扩容至新申请的容量
- 如果小于1024, 那么就直接两倍
- 如果大于1024,就按照1.25倍去扩容
- 具体存储的值类型不同,扩容策略也有一定的不同。
- 切片复制
1 | package main |
【注意】
-
切片不保存具体的值;
-
切片对应一个底层数组;
-
底层数组都是占用一块连续的内存;
- 简单的实例
1 | package main |
11、指针
&
取地址;*
根据地址取值;
1 | package main |
【make与new的区别】
- make和new都是用来申请内存的;
- new很少用,一般用来给基本数据类型申请内存你,
string
、int
,返回的是对应类型的指针; - make是用来给
slice
、map
、chan
申请内存的,make函数返回的是对应的这三个类型本身。
12、map
map是一种无序的基于key-value
的数据结构,Go语言中的map是引用类型,必须初始化才能使用。
- 基本使用
1 | package main |
- 排序与遍历
1 | package main |
- map与slice:元素为map类型的切片、值为切片类型的map
1 | package main |
13、函数
- 函数定义
1 | func 函数名(参数)(返回值){ |
- 基本使用
1 | package main |
- defer语句:会将其后面跟随的语句进行延迟处理,在
defer
归属的函数即将返回时,将延迟处理的语句按defer
定义的逆序进行执行,也就是说,先被defer
的语句最后被执行,最后被defer
的语句最先被执行。
1 | package main |
【defer的执行时机】
1 | package main |
- 变量作用域
函数中查找变量的顺序
- 先在函数内部查找
- 找不到就往函数的外面查找,一直找到全局
1 | package main |
- 函数类型与变量
1 | package main |
14、匿名函数
1 | package main |
15、fmt
1 | package main |
语法补充
1、time 包
1 | package main |
【注意】
- 格式化输出的不同,2006.01.02 03:04:05 pm
2、日志库
- 简单示例(往文件中写入)
1 | package main |
- 日志需求(一般情况)
- 支持往不同的地方输出
- 日志分级别
- debug
- Trace
- Info
- Warning
- Error
- Fatal
- 日志要支持开关控制
- 完整的日志记录要包含有时间、行号、文件名、日志级别、日志信息
- 日志文件要切割
3、反射
在Go语言的反射机制中,任何接口值都由是一个具体类型
和具体类型的值
两部分组成的。 在Go语言中反射的相关功能由内置的reflect包提供,任意接口值在反射中都可以理解为由reflect.Type
和reflect.Value
两部分组成,并且reflect包提供了reflect.TypeOf
和reflect.ValueOf
两个函数来获取任意对象的Value和Type。
- 通过反射获取对象的类型和值
- 通过反射设置对象的值
1 | package main |
- 结构体中的反射应用
1 | package main |
【反射是把双刃剑】
反射是一个强大并富有表现力的工具,能让我们写出更灵活的代码。但是反射不应该被滥用,原因有以下三个。
- 基于反射的代码是极其脆弱的,反射中的类型错误会在真正运行的时候才会引发panic,那很可能是在代码写完的很长时间之后。
- 大量使用反射的代码通常难以理解。
- 反射的性能低下,基于反射实现的代码通常比正常代码运行速度慢一到两个数量级。
4、strconv 包
1 | package main |