1. 搭环境
1.1下载Downloads - The Go Programming Language
傻瓜式安装
然后找到路径根目录下的bin文件
这里就是可执行go程序文件
win+r,写cmd回车,然后进入当前目录下,即在cmd内输入以下代码
cd D:/go/bin,回车
d:,回车
go version,回车
这时能看见版本号,就证明安装成功
这里,你可以直接尝试在任何目录下查看go版本,发现报错
这里的查找规则是,当输入命令后,会在当前目录下查找,找不到会去环境变量找,如果还找不到就报错
因为要配置环境变量,现在我们去配置,点计算机右键属性->高级系统设置->高级下面的环境变量->系统变量点新建
配置下列两项,第一项是根目录(即当时安装的目录)第二项是以后所有go项目放的位置
变量名GOROOT变量值D:\go
变量名GOPATH变量值D:\goPath
为什么path不用配置?我这里是使用1.18.x版本,安装的时候就配置了,不信你点击path编辑,然后看到
配置完后,点确定退出
最后重启cmd
然后直接输入,go version
好了,环境配置好了
2. 基本语法
2.1常用转义字符
\t,相当于tab
\n,换行
\\,斜杆
\",一个"
\r,一个回车,意思是/r后面的内容替换行内最开始的内容
2.2基本数据类型
2.3整数类型范围值
尽量往小的写
类型 | 有无符号 | 占据空间 | 取值范围 |
int8 | 有 | 1字节 | -128-127(-2^7-2^7-1) |
int16 | 有 | 2字节 | -2^15-2^15-1 |
int32 | 有 | 4字节 | -2^31-2^31-1 |
int64 | 有 | 8字节 | -2^63-2^63-1 |
uint8 | 无 | 1字节 | 0-255(0-2^8-1) |
uint16 | 无 | 2字节 | 0-2^16-1 |
uint32 | 无 | 4字节 | 0-2^32-1 |
uint64 | 无 | 8字节 | 0-2^64-1 |
byte | 无 | 1字节 | 0-255(0-2^8-1) |
rune | 有 | 4字节 | -2^31-2^31-1 |
2.4浮点类型取值范围
尽量使用双精度
类型 | 有无符号 | 占用空间 | 取值范围 |
单精度float32 | 有 | 4字节 | -3.403E38-3.403E38 |
双精度float64 | 有 | 8字节 | -1.798E308-1.798E308 |
2.5字符类型(char)
go中没有专门的字符类型,如果要存储单个字符(字母)(ascii),一般用byte保存
go的字符是用字节组成
var n = '0'//字符的0
fmt.Println(n)//输出ascii的48
fmt.Pringtf(n)//格式化输出,即0
2.6数据类型默认值
类型 | 默认值 |
int | 0 |
float | 0 |
bool | false |
string | "" |
2.7强制性语法
--和++只能独立使用(只有后++后--,没有前++前--)
除法运算不加0,永远是向下取整
go没有三元运算符
var num int = 0
num = num++//报错
var i int = 0
i++
num = i//正确写法
var n float64 = 10 / 3 //结果是3
var n float64 = 10.0 / 3 //结果是3.3333333333333335
switch语句不用跟break,可以穿透fallthrought
if语句不带小括号,可以在表达式里面进行赋值
if 表达式 {
走1
}else {
走2
}
if num int := 1 == 1 {
走1
}
循环,遍历字符串,用range关键字
或者转[]rune
go语言没有do while(),while()是用for循环实现
//用break跳出
var i int = 1
for{
if i > 10 {
break
}
fmt.Println("第",i,"个")
i++
}
for多层嵌套时,break可以使用标签指定跳出那一层
lable2:
for i := 0; i < 5 i++ {
for j := 0; j < 5 i++ {
break lable2//直接退出两层
}
}
go支持goto语句(无条件指定跳到某块代码执行),但不建议用,尽量少用
占位符_(下划线),又称忽略符,即:当可能不需要用到的变量,可以用_来不要报错
3. 包/函数
3.1包
- 在同一包内,不能有相同的包名(如果同一文件夹是一个包,包内的文件定义的函数不能重复)
- 引入的包,函数/变量首字母要大写
3.2函数的defer
函数内的defer会压入栈,等函数关闭再执行
package main
import (
"fmt"
)
func sum(n1 int, n2 int) int {
defer fmt.Println("1---", n1)//--------1
defer fmt.Println("2---", n2)//--------2
res := n1 + n2
fmt.Println("sum---res", res)//--------3
return res
}
func main() {
res := sum(10, 20)
fmt.Println("main---res", res)//-------4
}
执行顺序:3 -> 2 -> 1 -> 4
3.3字符串函数
len()计算字符串长度
如果字符串中含中文,则使用切片[]rune()转换
字符串转整数,nil相当于null,strocnv.Atoi()
n, err := strconv.Atoi("hello")
if err != nil {
fmt.Println("转换错误", err)
}else {
fmt.Println("装换的结果是", n)
}
整数转字符串,strconv。Itoa()
字符串转byte,[]byte()
10进制转别的进制,strconv.FormatInt()
字符串中是否包含别的字符串,一参字符串,二参是否包含的字符串,返回boolean,strings.Contains()
查找,strings.Index(),strings.LastIndex()
替换,原字符串不变,strings.Replace()
拆分,strings.Split()
转小写,strings.ToLower(),转大写,strings.ToUpper()
去掉左右空格,strings.TrimSpace(),strings.Trim(),strings.TrimLeft(),strings.TrimRight()
是否指定字符串开头/结尾,返回boolean,strings.HasPrefix(),strings.HasSuffix()
3.4时间日期函数
获取当前时间,now := time.Now()
基于上面一行,获取其他
now.Year()年 | now.Month()月 | now.Day()日 | now.Hour()时 | now. minute()分 | now.Second(秒 |
格式化日期,据说这个日期的格式是固定了,为的是纪念当时go语言的诞生,数字不能改变
now.Format("2006/01/02 15:04:05")
now.Format("2006-01-02 15:04:05")
时间的常量
Nanosecnd Duration纳秒 | Microsecond微秒 | Second秒 | Minute分 | Hour时 |
休眠
time.Sleep()
1秒,×1个一千毫秒,×2个一千微秒,×3个一千就是纳秒,×4个一千皮秒
从19700101到现在获取秒数和纳秒数,now.Unix(),now.UnixNano()
3.5内置函数
new分配内存,make分配引用内存
错误处理,在go中不支持try,catch
捕获异常函数,ercover(),采用defer+ercover()来处理异常,这样能保持后面代码能正常执行
4. 数组/切片
4.1数组基本语法
// 定义一个长度3数组
var arr = [3]int
// 定义一个数组,不限制长度
var arr1 = [...]int
// 定义一个数组,并初始化
var arr2 = [3]int {1, 2, 3}
// 定义一个数组,指定下标
var arr3 = [3]string {1:" ", 0:"hello", 2:"world"}
数据遍历方法
①常规for遍历
②for-range遍历
var arr = [...]string{"one", "two", "three"}
// i就是index,v就是value
for i, v := range arr {
fmt.Printf("i = %v , v = %v",i, v)
}
使用指针修改数组
// 修改函数
func change (arr *[3]int) {
(*arr)[0] = 100 // 拿到地址,然后解一下,拿到值,进行赋值
}
var arr = [3]int {1, 2, 3}
change(&arr)// 传地址
fmt.Println(arr)// [100 2 3]
数组细节
①类型确定了就不能写别的类型
②长度确定了,就不能动态改变
4.2切片
数组是值类型
切片是引用类型
①切片长度是可以动态变化的
切片又称slice,我用s
基本使用
var arr [5]int = [...]int {11, 22, 33, 44, 55}
// 定义一个切片,然后截取数组的第1个元素,到第3个元素,不包含3
var s = arr[1:3]
fmt.Println("s = ", s)// [22, 33]
fmt.Println("len = ", len(s))// 长度2
fmt.Println("cap = ", cap(s))// 内置函数,切片的容量,4,切片的容量根据切片长度自动扩容
切片在内存里面就存3个东西
①引用的地址,
②切片的长度
③切片的容量
使用make内置函数创建切片,一参类型,二参长度,三参容量
var s []float64 = make(float64, 5, 10)
s[1] = 11
fmt.Println("s = ", s) // [0, 11, 0, 0, 0]
fmt.Println("len = ", len(s))// 长度5
fmt.Println("cap = ", cap(s))// 容量为10
以上两种的区别?面试题
前者,直接引用数组,数组是存在的,可见的
后者,使用make创建的切片,由make创建数组,在切片底层进行维护,不可见的
切片的遍历
常规for或者for-range遍历,这里不再演示
切片细节
①切片初始化时,不能越界
②简写语法
从第0个开始,s[0:4],简写s[:4]
从n到最后一个,s[1:4],简写s[1:]
全部,s[0:len(s)],简写[:]
③切片后可以再切片
使用append内置函数追加切片,在内存中是会先拷贝一个数组,然后重新指向这个新的数组
var arr [5]int = [...]int {11, 22, 33, 44, 55}
// 定义一个切片,然后截取数组的第1个元素,到第3个元素,不包含3
var s = arr[1:3]
s = append(s, 66, 77)// 追加
fmt.Println("s = ", s)// [11 22 33 44 55 66]
s = append(s, s...) // 追加自己
fmt.Println("s = ", s)// [11 22 33 44 55 66 11 22 33 44 55 66]