01.Go语言基础语法易错点总结
一.基础语法易错知识点
(一).数据类型
1.Golang是强类型语言。
2.在赋值过程中、类型必须保持一致。
3.变量必须先定义后使用,且必须用到。
4.golang会为每个变量设置默认值。
5.变量不能重名。
6.golang会根据类型做变量类型推断。
7.代码规范
- 变量一般都是有小驼峰命名法
- 如果外部引用 用大驼峰命名法
- 数据库使用大驼峰命名法
8.数据库ORM参考学习
https://github.com/go-gorm/gen
9.字符串和整型互转案例
numType := 100
fmt.Printf("Type: %T\n",strconv.Itoa(numType))
str := "1000"
ret,_ := strconv.Atoi(str)
fmt.Printf("Type:%T\n",ret)
10.如下测试改变的是盒子里面放的内容,而不是盒子。
age := "23"
fmt.Printf("getMemoryAddress: %p\n",&age)
age = "24"
fmt.Printf("getMemoryAddress: %p\n",&age)
11.变量不可以重名 但是在新的作用域内是可以同名
{
var age string
age = "jesseAge"
fmt.Printf("我是新的作用域:%v\n",age)
}
12.常量在整个生命周期都不允许修改。
- 常量是在编译过程中计算好的值。
- 变量是在运行过程中配置的值。
- 常量只能支持: bool/string/数字。
- 变量没有限制。
13.goland中 alt + shift+鼠标滑动 可以复制列。
- alt+鼠标左键 单击选中多个光标进行修改。
14.运算符中a/b 如果都是int类型 结果将会舍去小数位直接显示整数位 需要也别注意。
15.位运算案例
func bitCalc(){
arr := []int{4,-3,4,5,6,-3,5,6,7}
ret := -1
for _,v := range arr{
if ret <0 {
ret = v
fmt.Printf("ret<0: %v\n",ret)
}else {
ret = ret ^ v
fmt.Printf("ret>=0: %v\n",ret)
}
}
fmt.Printf("最终ret变量结果: %v\n",ret)
}
16.fmt有迷惑性参数汇总
%p # 表示为十六进制,并加上前导的0x
%f # 默认宽度,默认精度
%9f # 宽度9,默认精度
%.2f # 默认宽度,精度2
%9.2f # 宽度9,精度2
%9.f # 宽度9,精度0
17.课程涉及站点
http://doc.golang.ltd/
https://github.com/boltdb/bolt/
https://crontab.guru/
https://golangdocs.com/
https://blog.gopheracademy.com/
https://www.manning.com/books/the-programmers-brain
https://forge.medium.com/the-easiest-thing-you-can-do-to-make-a-boring-job-better-7166d9e9e202
18.指定平台编译方式
GOOS=windows GOARCH=amd64 go build -o bfr_x64.exe ./main.go //64bit Win
GOOS=windows GOARCH=386 go build -o bfr_x32.exe ./main.go //32bit Win
GOOS=linux GOARCH=amd64 go build -o bfr_x64_linux ./main.go //64bit Linux
19.go mod初始化方式
go mod init gocamp_home_study
20.pprof 性能分析相关
https://golang.google.cn/pkg/runtime/pprof/
https://golang.google.cn/pkg/net/http/pprof/#Index
https://github.com/google/pprof/
https://studygolang.com/articles/12970
21.keymap可以设置快捷键
22.General->Appearance->show whitespace 显示隐藏的字段。
23.NaN: not a number的简写。
24.windows->editor Tabs->split right/down // 分屏
25.双引号 单引号 反引号
- 单引号表示byte类型或rune类型,对应uint8和int32类型,默认是rune类型。byte用来强调数据是raw data,而不是数字,而rune用来表示Unicode的code point。
- 双引号才是字符串,实际上是字符数组。可以用索引号访问某字节,也可以用len()函数来获取字符串所占的字节长度。
- 反引号,表示字符串字面量,但不支持任何转义序列。字面量raw literal string的意思是,你定义时写的啥样,它就啥样,你有换行,它就换行。你写转义字符,它也就展示转义字符。
//示例
func quoteTest(){
//双引号"",可转义。
x := "x\nquote\ttest"
fmt.Printf("x is:%v,type is %T\n",x,x)
//反引号``,保持原有格式输出
var codeExample string =`
func main(){
fmt.Println("Hi Jesse~")
}
`
fmt.Println(codeExample)
//单引号'',通常用来表示rune类型,展示unicode。
var a byte = 'H'
fmt.Printf("a:%v,type:%T\n",a,a)
b := '你'
fmt.Printf("b:%v,type:%T\n",b,b)
}
//结果
a:72,type:uint8
b:20320,type:int32
26.字符串是utf-8编码,一个汉字三个字节,一个字母一个字节。
//utf-8它可以使用1-4个字节表示一个字符,根据字符的不同变换长度。
//字符长度和字节长度理解
https://mp.weixin.qq.com/s/pXO4LxehqENEvRvxCXhG4A
27.Goland todo关键字
//fixme 待修复bug
//todo 待做事项
28.generate->Implement Methods
- 自动创建未实现的方法。
29.选中字段名->refactor->rename // 批量修改
30.alt+shift+command+F 代码快速格式化
31.Mac下常用键盘符对应关系
⌘(command)
⌥(option)
⇧(shift)
⇪(caps lock)
⌃(control)
↩(return)
⌅(enter)
如果不记得了 可以选择Mac下右上角的输入法图标,选择虚拟键盘即可看到对应关系。
(二).位操作符
1.与操作:&
1 & 1 = 1
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0
#(The result of 5&6 is ', 4)
5 二进制为 101
6 二进制为 110
按照&的计算规则 相同为1 相异为0 5&6的结果二进制100 二进制100对应上面的4。
2.或操作:|
1 | 1 = 1
1 | 0 = 1
0 | 1 = 1
0 | 0 = 0
('The result of 5|6 is ', 7)
5 二进制为 101
6 二进制为 110
按照|的计算规则 只要有一个为1 结果就为1,5|6的结果二进制111 二进制111对应上面的7。
3.异或:^ 同0异1
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0
('The result of 5^6 is ', 3)
5 二进制为 101
6 二进制为 110
按照|的计算规则 上下对应相异 结果就为1 5^6的结果二进制011 二进制011对应上面的3 正常情况会忽略前面的0。
4.左移:<<
1 << 2 = 4
('The result of 1<<2 is ', 4) #1左移2位
0000 0001 #1的二进制如左边 所有位数左移2位
0000 0100 #左移2位结果如左边 对应十进制的4
5.右移:>>
8 >> 2 = 2
('The result of 8>>2 is ', 2) #8右移2位案例
0000 1000 #8的二进制。
0000 0010 #所有右移2位结果 对应十进制2的二进制。
(二).源码/反码/补码
(三).array
1.自动计算数组的长度,不用再刻意定义。
arr := [...]int{1,2,3,4,5}
fmt.Println(arr)
2.数组赋值
//如果没有赋值 默认结果为 a = [3]int{0,0,0}
a := [3]int{}
a[0]=1
a[1]=2
a[2]=3
3.数组和多维数组核心知识点测试代码
//测试定长数组
func arrayExample1(x [5]int){
//原始值
fmt.Println(x)
//for循环打印结果方式
for i:=0;i<len(x);i++{
fmt.Printf("for: x[%d]=%d\n",i,x[i])
}
//for range 遍历数组打印结果方式
for k,v := range x{
fmt.Printf("range: x[%d]=%d\n",k,v)
}
}
//测试变长 切片实现
func arrayExample2(array2 []int){
for i:=0;i<len(array2);i++{
array2[i] = i+99
}
fmt.Println(array2)
//测试数组长度自动计算获取
array3 := [...]int{1,1,1,1,1}
fmt.Println(array3)
}
//测试多维数组
func arrarExample3(){
var arr3 [3][3]int
arr3 = [3][3]int{{1,2,4},{2,4,6},{23,23,23}}
fmt.Println(arr3)
//数组设置为变长
var arr4 = [...][3]string{
[3]string{"Jesse","23","engineer1"},
[3]string{"Jesse1","24","engineer2"},
[3]string{"Jesse2","25","engineer3"},
[3]string{"Jesse3","26","engineer4"},
[3]string{"Jesse4","27","engineer5"},
[3]string{"Jesse5","28","engineer6"},
[3]string{"Jesse6","29","engineer7"},
}
for _,v := range arr4{
fmt.Println(v)
}
//多重遍历取最终值
for x,y :=range arr4{
for x1,y2 := range y{
fmt.Printf("arr4[%d][%d]=%v\n",x,x1,y2)
}
}
}
(四).slice
1.slice中一些比较关键的操作
- 第一种
make([]Type ,length, capacity)
slice := make([]int, 3, 5)
- 第二种
make([]Type, length)
slice := make([]int, 5)
- 第三种
[]Type{}
slice := []int{}
- 第四种
slice := []int{1, 2, 3, 4, 5} //len是根据初始化长度而定的
- 第五种
//append内部实现了slice的自增,内部进行了make初始化。
//append无论如何都是从slice的尾部开始追加数据,每次append 都要重新分配一次内存。
func sliceStudy() {
//追加元素
a := []int{11, 22, 33}
b := []int{1, 2, 3, 4, 4, 5}
//如果append的数据为切片 别忘记...
a = append(a, b...)
fmt.Println("将b切片追加到a切片中。")
fmt.Println(a)
//删除元素4 ...表示追加多个元素
c := []int{1, 2, 3, 4, 5, 6, 7, 8}
c = append(c[:3], c[4:]...)
fmt.Println(c)
//删除多个元素 3 7 8
d := []int{1, 2, 3, 4, 5, 6, 7, 8}
d = append(d[:3], d[4:6]...)
fmt.Println(d)
}
//copy以最小的为基准
func copySlice(){
x := make([]int,4) //dst
y := []int{1,2,3} //src
copy(x,y)
fmt.Println(x)
}
(五).map
1.map注意事项
- 不用实例化就可以读取 删除。
- 必须实例化才可以写入。
- 重复删除相同的key,不会引起异常。
2.map初始化和案例
- 第一种初始化方式
var numbers map[string]int
numbers = make(map[string]int)
- 第二种声明并初始化
number := make(map[string]int)
- 案例
func mapExample1() {
m4 := map[string]int{"name": 1, "sex": 2, "addr": 3}
m4["name"] = 111
fmt.Println("m4:modify", m4)
delete(m4, "sex")
fmt.Println("m4:delete", m4)
_, ok := m4["addr"]
if ok {
fmt.Println(m4["addr"])
}
//遍历map
for k,v := range m4{
fmt.Printf("k=%v,v=%v\n",k,v)
}
}