Go 语言基础¶
Go 程序基本结构¶
包声明¶
包名要求
- 与目录保持一致
- 不要冲突标准库
包导入¶
- 使用(公开)函数:先导入,调用时
pkgName.funcName - Go 标准库 API 存放在
go/src/.../xxx.go中
程序主体¶
func为关键字,函数声明- 转义字符:
\t、\n、\r、\\、\"等
注释¶
变量¶
Go要求
- 必须以
go作为扩展名 - 入口为
main()函数 - 严格区分大小写
- 语句无需分号(自动加)
- 一行只能写一个语句
- 引入的包*必须*使用,定义的变量*必须*使用(否则编译不过)
- 大括号成对出现,缺一不可
Go 控制台命令¶
graph LR
A-->|go build|B[可执行文件] -->|运行| D[结果]
A-..->|go run|D
go build xxx.go将xxx.go文件生成可执行文件- 可执行文件在当前目录下生成,在命令行下可以直接执行
- 这个文件可以拷贝到没有 go SDK 的环境下运行
go run xxx.go包含编译和运行两步- 脚本式执行,速度较慢
go fmt xxx.go格式化代码-w选项将修改写入源文件
Go 数据类型¶
基本数据类型¶
基本类型默认值
| 类型 | 默认值 |
|---|---|
| 数值(int、float) | 0 |
| 字符串 | "" |
| 布尔 | false |
数值¶
intuintx(x=8,16,32,64)无符号整型,x为占用字节数intx(x=8,16,32,64)有符号整型,x为占用字节数byte为int8别名;rune为int32别名,表示一个unicode码。
float:float32、float64(默认),浮点型,支持科学计数法a.e(E)B=a*10^Bcomplex:complex64、complex128,复数
字符¶
使用
byte保存单个字符
- 如果直接输出,会输出其 ASCII 码值,所以需要使用格式化输出
fmt.Printf()%c说明符- 如果需要输出中文,请使用一个可容纳的类型(如
int)
- 如果需要输出中文,请使用一个可容纳的类型(如
- 在运算时,字符类型相当于一个整数
- Go 语言的字符是utf-8编码
布尔bool¶
用于流程控制 if、for 等
字符串string¶
- Go 字符串由字节组成,一旦赋值就不可变
- 字符串的两种表示形式
- 双引号:
"hello",创建可解析的字符串字面量(支持转义,但不能用来引用多行) - 反引号:
`hello`,创建原生的字符串字面量,这些字符串可能由多行组成(不支持任何转义序列),原生的字符串字面量多用于书写多行消息、HTML以及正则表达式
- 双引号:
- 字符串的拼接,用加号
+。- 多行代码中,
+要留在上一行
- 多行代码中,
- 字符串函数
- 统计长度
len(str)(按字节) - 遍历字符串
- 字符串转整数
strconv.Atoi(str) - 子字符串判断
strings.Contains(s string, substr string) bool - 一个字符串有几个指定字串
strings.Count(s string, sep string) int - 不区分大小写的字符串比较
strings.EqualFold(s1, s2 string) bool- 直接
==是区分大小写的比较
- 直接
- 子串第一次出现位置
strings.Index(s string, sub string) int - 字串最后一次出现位置
strings.LastIndex(s string, sub string) int - 替换
strings.Replace(s string, origin string, substitute string, n int) strings本身不会变化n替换几次,-1为全部
- 按指定字符分割
strings.Split(s string, sep string) []string - 大小写转换:
strings.ToLower(s string) string、strings.ToUpper(s string) string - 去两边空格
strings.TrimSpace(s string) string - 去指定字符
strings.Trim(s string, cutset string) string- 去左边
strings.TrimLeft(s string, cutset string) string - 去右边
strings.TrimRight(s string, cutset string) string
- 去左边
- 前后缀
- 前缀
strings.HasPrefix(s string, prefix string) bool - 后缀
strings.HasSuffix(s string, suffix string) bool
- 前缀
- 统计长度
基本数据类型转换¶
- 显式转换
var <varname> <type2> = <type2> (var1) - 转化为字符串
fmt.Sprintf("%参数", 表达式) stringint:%dfloat:%fbool:%t- ……
strconv包strconv.FormatX(i int64, base int) string- X=Bool, Int, Float, Uint
strconv.Itoa(int)
var str = string(byte数组)
-
字符串转基本类型
strconv包strconv.ParseX(X=Bool, Int, Float, Uint)- 返回值为64位的,需要32位要再次强转
- 转化为整数
strconv.Atoi(str)(n int, err error)- 等价于
parseInt(str, 10)
- 等价于
var bytes = []byte(str)
不能转换的字符串,直接转换为默认值
派生/复杂数据类型¶
- 指针:存的是变量的地址
- 指针变量:
var ptr *<type>指向type类型的ptr - 获取地址:
&var - 获取其中存储的值:
*ptr int、float、bool、string(值类型)、数组、结构体都有对应的指针类型
- 指针变量:
-
数组:存放多个同一数据类型
- Go中的数组是值类型
- 声明:
var 数组名 [数组大小]数据类型 - 一旦确认不可改变长度
- 赋值:
数组名[下标]=值 - 访问:
数组名[下标] - 初始化
- 遍历
- 数组传参
- 值传递:传递的是数组的副本,不会影响原数组
func test(arr []int) {...} - 引用传递:传递的是数组的地址,会影响原数组
func test(arr *[3]int) {...}
- 值传递:传递的是数组的副本,不会影响原数组
-
二维数组
var arr[2][3] int[][]=[2][3]int{{1,2,3}{4,5,6}}(第一维可省略)-
遍历 === "普通for"
-
-
切片:不确定数量的集合
- 切片属于引用类型,传递也传送地址
- 声明:
var 变量名 []类型 - 容量
cap(),元素个数len() - 从底层来看,是一个 struct 结构体
- 使用
- 定义切片,并引用一个数组
make([], len, [cap])- 指定具体数组
[start:end],含arr[start],不含arr[end]arr[:end],从头到endarr[start:],从start到尾arr[0:len(arr)]=arr[:],全部
- 遍历:类似数组
append(slice[] Type, elems... Type)动态增加项目- 具体元素
xx:=append(slice, 10, 20, 30) - 切片
xx:=append(slice, slice2...)
- 具体元素
- 拷贝
copy(para1,para2),从切片para2拷贝到para1
-
映射
- 声明:
var map变量名 map[keyType] valueType,key不能重复,value可以相同- slice、map、function 不可以作为key
- 分配内存后才能赋值和使用
- 声明→make→使用
- 声明时make→使用
- 直接赋值
- 增删改查
map["key"]=value(实质为val, res:=map["key"],其中res为布尔值)- key 存在(
res为true),则修改 - key 不存在(
res为false),则添加
- key 存在(
delete(map,"key")- key 存在,则删除
- key 不存在或为 nil,则无操作(并不会报错)
- 遍历
for k,v:= range Map{...} - 长度
len(map)返回值为几对键值对 - 切片
[]map [keyType]valueType,动态增加用append() - 排序:借助切片
如何清空map?
- 遍历,逐个删除
- make一个新的,原来的交给gc回收处理
- 声明:
- 结构体
- 接口
- 管道
自定义数据类型¶
Go 支持自定义数据类型 type <别名> <数据类型>,相当于C的 typedef
Go 标识符¶
- 可以使用 26 个英文字母大小写、0-9、下划线
- 变量名、函数名、常量名一般使用驼峰法
- 首字母大写是公开的(可从 GoPath 导入包名和变量名),小写是私有的(在本包使用)
Go 运算符¶
Go 无三元运算符
- 算术运算
- 加
+ - 减
- - 乘
* - 除
/- 整数除法,结果只保留整数部分(
10/4=2,而10.0/4=2.5)
- 整数除法,结果只保留整数部分(
- 取模
%a%b=a-a/b*b
- 自增
++- 只有后置自增
i++,没有前置自增++i
- 只有后置自增
- 自减
--- 只有后置自减
i--,没有前置自减--i
- 只有后置自减
- 位运算:
&、|、^、<<、>>
- 加
- 判断符号:
==!=><>=<= - 逻辑运算:
&&||!&&和||支持短路操作
输入与输出¶
主要使用
fmt包
fmt.Scanln():在换行时停止扫描(与C类似,扫描到变量所指向的地址(&var)中)fmt.Scanf():格式化输入- 常用格式符:
%d整数、%f小数、%s字符串、%t布尔值
- 常用格式符:
fmt.Println():输出后换行
时间与日期¶
主要使用
time包
time.Time类型表示时间now:=time.Now()表示当前时间- 实例方法:年
now.Year()、月now.Month()、日now.Day()、时now.Hour()、分now.Minute()、秒now.Second(),需要数字可以使用int()强制转换 - 格式化:
now.Format("2006-01-02 15:04:05"),其中2006-01-02 15:04:05是固定格式
- 实例方法:年
- 时间常量:
time.Second、time.Minute、time.Hour、time.Day、time.Week、time.Month、time.Year - 其它常见方法
time.Sleep(d Duration)time.Unix()time.UnixNano()
文件操作¶
os.File结构体表示文件
- 打开文件
os.Open(name string)(file *File, err error)os.OpenFile(name string, flag int, perm FileMode) (*File, error)
- 关闭文件
func (*File) Close() error- 函数退出时,及时关闭File(
defer file.Close()),否则会有内存泄漏
- 函数退出时,及时关闭File(
- 读取文件
bufio.NewReader(file) *Reader:创建一个缓冲区(大小4096),用于读取文件func (*Reader) ReadString() (string, error):读取文件内容,直到遇到换行符
ioutil.Readfile(filepath string) ([]byte, error):一次性读取文件内容- 无需调用
Open()、Close()
- 无需调用
- 写入文件
bufio.NewWriter(file) *Writer:创建一个缓冲区(大小4096),用于写入文件func (*Writer) WriteString() (int, error):写入文件内容(到缓冲区)- 注意
WriteString()后内容在缓存中没有进磁盘,一定要紧接调用Flush()
ioutil.WriteFile(filepath string, data []byte, perm os.FileMode) error:一次性写入文件内容- 无需调用
Open()、Close()
- 无需调用
- 文件信息
os.Stat(name string) (FileInfo, error)os.IsExist(err error) bool:判断文件是否存在os.IsNotExist(err error) bool:判断文件是否不存在
- 拷贝文件
io.Copy(dst Writer, src Reader) (written int64, err error)返回第一个参数是已拷贝字节数
- 命令行参数
os.Args,类型为[]string,其中第一个元素为程序名- 解析参数:
flag包flag.XXXVar(p *XXX, name string, value string ,usage string) flag.Parse():解析参数,必须在所有参数定义之后调用