进度一
#  一、Go 基本语法
和 js,python 语法类似,具体见菜鸟教程,C 语言中文网 等,这里只记录难点
 
#  (一) 数组#  一维数组
初始化及遍历 
 
1 2 3 4 5 6 7 8 9 10 11 var  a [3 ]int              fmt.Println(a[0 ])         fmt.Println(a[len (a)-1 ])  for  i, v := range  a {    fmt.Printf("%d %d\n" , i, v)   } for  _, v := range  a {    fmt.Printf("%d\n" , v) } 
在数组的定义中,如果在数组长度的位置出现 “…” 省略号,则表示数组的长度是根据初始化值的个数来计算,因此,上面数组 q 的定义可以简化为:
1 2 q := [...]int {1 , 2 , 3 } fmt.Printf("%T\n" , q)  
#  循环遍历 range1 2 3 4 5 6 slice := []int {10 , 20 , 30 , 40 } for  index, value := range  slice {    fmt.Printf("Index: %d Value: %d\n" , index, value) } 
切片 
 
根据索引位置取切片 slice 元素值时,取值范围是(0~len (slice)-1),超界会报运行时错误,生成切片时,结束位置可以填写 len (slice) 但不会报错。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var  highRiseBuilding [30 ]int for  i := 0 ; i < 30 ; i++ {        highRiseBuilding[i] = i + 1  } fmt.Println(highRiseBuilding[10 :15 ]) fmt.Println(highRiseBuilding[20 :]) fmt.Println(highRiseBuilding[:2 ]) 
结果:
1 2 3 [11  12  13  14  15 ] [21  22  23  24  25  26  27  28  29  30 ] [1  2 ] 
动态创建切片,可以使用 make () 内建函数,格式如下:
1 make ( []Type, size, cap  )
其中 Type 是指切片的元素类型,size 指的是为这个类型分配多少个元素,cap 为预分配的元素数量,这个值设定后不影响 size,只是能提前分配空间,降低多次分配空间造成的性能问题。
1 2 3 4 5 a := make ([]int , 2 ) b := make ([]int , 2 , 10 ) fmt.Println(a, b) fmt.Println(len (a), len (b)) 
结果:
其中 a 和 b 均是预分配 2 个元素的切片,只是 b 的内部存储空间已经分配了 10 个,但实际使用了 2 个元素。
容量不会影响当前的元素个数,因此 a 和 b 取 len 都是 2。
而为切片添加元素则与 python 类似,使用内建函数 append ()
1 2 3 4 var  a []int a = append (a, 1 )  a = append (a, 1 , 2 , 3 )  a = append (a, []int {1 ,2 ,3 }...)  
#  多维数组声明:
1 2 3 4 5 6 7 8 var  array [4 ][2 ]int array = [4 ][2 ]int {{10 , 11 }, {20 , 21 }, {30 , 31 }, {40 , 41 }} array = [4 ][2 ]int {1 : {20 , 21 }, 3 : {40 , 41 }} array = [4 ][2 ]int {1 : {0 : 20 }, 3 : {1 : 41 }} 
#  (二)函数#  1. 声明1 2 3 func  函数名(形式参数列表)     函数体 } 
如:
1 2 3 4 func  hypot (x, y float64 ) float64  {    return  math.Sqrt(x*x + y*y) } fmt.Println(hypot(3 ,4 ))  
#  2. 调用函数在定义后,可以通过调用的方式,让当前代码跳转到被调用的函数中进行执行,调用前的函数局部变量都会被保存起来不会丢失,被调用的函数运行结束后,恢复到调用函数的下一行继续执行代码,之前的局部变量也能继续访问。
函数内的局部变量只能在函数体中使用,函数调用结束后,这些局部变量都会被释放并且失效。
Go 语言的函数调用格式如下:
例如,加法函数调用样式如下:result := add (1,1)
#  3. 匿名函数#  1) 在定义时调用1 2 3 func (data int )     fmt.Println("hello" , data) }(100 ) 
#  2) 赋值给变量1 2 3 4 5 6 7 f := func (data int )      fmt.Println("hello" , data) } f(100 ) 
#  3) 用作回调函数1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package  mainimport  (    "fmt"  ) func  visit (list []int , f func (int )     for  _, v := range  list {         f(v)	     } } func  main ()          visit([]int {1 , 2 , 3 , 4 }, func (v int )          fmt.Println(v)	     }) } 
#  结合命令行将匿名函数作为 map 的键值,通过命令行参数动态调用匿名函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package  mainimport  (    "flag"      "fmt"  ) var  skillParam = flag.String("skill" , "" , "skill to perform" )func  main ()     flag.Parse()     var  skill = map [string ]func ()          "fire" : func ()              fmt.Println("chicken fire" )         },         "run" : func ()              fmt.Println("soldier run" )         },         "fly" : func ()              fmt.Println("angel fly" )         },     }     if  f, ok := skill[*skillParam]; ok {         f()     } else  {         fmt.Println("skill not found" )     } } 
代码说明如下:
第 8 行,定义命令行参数 skill,从命令行输入 --skill 可以将 =  后的字符串传入 skillParam 指针变量。 
第 12 行,解析命令行参数,解析完成后,skillParam 指针变量将指向命令行传入的值。 
第 14 行,定义一个从字符串映射到 func () 的 map,然后填充这个 map。 
第 15~23 行,初始化 map 的键值对,值为匿名函数。 
第 26 行,skillParam 是一个 *string 类型的指针变量,使用 *skillParam 获取到命令行传过来的值,并在 map 中查找对应命令行参数指定的字符串的函数。 
第 29 行,如果在 map 定义中存在这个参数就调用,否则打印 “技能没有找到”。 
 
运行代码,结果如下:
1 2 3 4 PS D:\code> go  run main.go  --skill=fly angel fly PS D:\code> go  run main.go  --skill=run soldier run  
#  (三) 接口调用1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package  mainimport  (    "fmt"  ) type  Invoker interface  {         Call(interface {}) } type  Struct struct  {} func  (s *Struct) interface {}) {    fmt.Println("from struct" , p)  } type  FuncCaller func (interface {}) func  (f FuncCaller) interface {}) {	          f(p) } func  main ()          var  invoker Invoker          s := new (Struct)          invoker = s          invoker.Call("hello" )                invoker = FuncCaller(func (v interface {})          fmt.Println("from function" , v)     })          invoker.Call("hello" ) } 
#  二、一些 demo#  (一)go 读取 pdf 中的纯文本内容#  1. 安装组件库1 2 go  get -u github.com/ledongthuc/pdfgo  mod vendor
安装过程中报错:
1 connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.  
解决方法:
改成我们国内可用的代理地址,在命令提示符输入: go env -w GOPROXY=https://goproxy.cn , 然后再做各种操作就可以成功了。
#  2. 运行1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package  mainimport  (	"bytes"  	"fmt"  	"github.com/ledongthuc/pdf"  ) func  main () 	pdf.DebugOn = true  	content, err := readPdf("test.pdf" )  	if  err != nil  { 		panic (err) 	} 	fmt.Println(content) 	return  } func  readPdf (path string ) string , error ) {	f, r, err := pdf.Open(path) 	 	defer  f.Close() 	if  err != nil  { 		return  "" , err 	} 	var  buf bytes.Buffer 	b, err := r.GetPlainText() 	if  err != nil  { 		return  "" , err 	} 	buf.ReadFrom(b) 	return  buf.String(), nil  } 
运行结果如下:
#  (二) Go 连接数据库安装依赖
1 go  get -u github.com/go -sql-driver/mysql
#  1. go 连接 MySQL1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package  mainimport  (	"database/sql"  	"fmt"  	_ "github.com/go-sql-driver/mysql"   ) func  main () 	 	 	dsn := "root:123456@tcp(127.0.0.1:3306)/testgo"  	 	db, err := sql.Open("mysql" , dsn)  	if  err != nil  { 		fmt.Printf("dsn:%s invalid,err:%v\n" , dsn, err) 		return  	} 	err = db.Ping()  	if  err != nil  { 		fmt.Printf("open %s faild,err:%v\n" , dsn, err) 		return  	} 	fmt.Println("连接数据库成功~" ) } 
#  实现增删查改首先在 mysql 的 testgo 中创建 user 表,实例有三个字段
1 2 3 4 5 6 CREATE TABLE `user`(     `id` BIGINT(20) NOT NULL AUTO_INCREMENT,     `name`  VARCHAR(20) DEFAULT '',     `age`   INT(11) DEFAULT '0',     PRIMARY KEY (`id`) )ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; 
建表成功后如下:
#  增加 DB1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 package  main  import  (	"database/sql"  	"fmt"  	_ "github.com/go-sql-driver/mysql"   )   var  db *sql.DB func  initDB () error ) {	 	 	dsn := "root:123456@tcp(127.0.0.1:3306)/testgo"  	 	db, err = sql.Open("mysql" , dsn)  	if  err != nil  { 		return  	} 	err = db.Ping()  	if  err != nil  { 		return  	} 	fmt.Println("连接数据库成功~" ) 	 	db.SetMaxIdleConns(10 ) 	return  }     func  insert () 	sqlStr := `insert into user(name,age) values("加油呀",28)`  	ret, err := db.Exec(sqlStr) 	if  err != nil  { 		fmt.Printf("insert failed,err:%v\n" , err) 		return  	} 	 	id, err := ret.LastInsertId() 	if  err != nil  { 		fmt.Printf("get id failed,err:%v\n" , err) 		return  	} 	fmt.Println("id" , id) }     func  main () 	err := initDB() 	if  err != nil  { 		fmt.Printf("init DB failed,err%v\n" , err) 	}   	 	insert() } 
#  删除1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package  main  import  (	"database/sql"  	"fmt"  	_ "github.com/go-sql-driver/mysql"   )   var  db *sql.DB func  initDB () error ) {	 	 	dsn := "root:123456@tcp(127.0.0.1:3306)/testgo"  	 	db, err = sql.Open("mysql" , dsn)  	if  err != nil  { 		return  	} 	err = db.Ping()  	if  err != nil  { 		return  	} 	fmt.Println("连接数据库成功~" ) 	 	db.SetMaxIdleConns(10 ) 	return  } func  deleteRow (id int ) 	sqlStr := `delete from user where id=?`  	ret, err := db.Exec(sqlStr, id) 	if  err != nil  { 		fmt.Printf("delete faild,err:%v\n" , err) 		return  	} 	n, _ := ret.RowsAffected() 	fmt.Printf("删除了%d行数据\n" , n)   }   func  main () 	err := initDB() 	if  err != nil  { 		fmt.Printf("init DB failed,err%v\n" , err) 	} 	 	deleteRow(1 ) } 
#  修改1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package  main  import  (	"database/sql"  	"fmt"  	_ "github.com/go-sql-driver/mysql"   )   var  db *sql.DB func  initDB () error ) {	 	 	dsn := "root:123456@tcp(127.0.0.1:3306)/testgo"  	 	db, err = sql.Open("mysql" , dsn)  	if  err != nil  { 		return  	} 	err = db.Ping()  	if  err != nil  { 		return  	} 	fmt.Println("连接数据库成功~" ) 	 	db.SetMaxIdleConns(10 ) 	return  }   func  updateRow (newAge int , id int ) 	sqlStr := `update user set age=? where id=?`  	ret, err := db.Exec(sqlStr, newAge, id) 	if  err != nil  { 		fmt.Printf("update failed ,err:%v\n" , err) 		return  	} 	n, _ := ret.RowsAffected() 	fmt.Printf("更新了%d行数据\n" , n) }   func  main () 	err := initDB() 	if  err != nil  { 		fmt.Printf("init DB failed,err%v\n" , err) 	}   	 	updateRow(20 , 1 )   } 
#  查找1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 package  main  import  (	"database/sql"  	"fmt"  	_ "github.com/go-sql-driver/mysql"   )   type  user struct  {	id   int  	name string  	age  int  }   var  db *sql.DB func  initDB () error ) {	 	 	dsn := "root:123456@tcp(127.0.0.1:3306)/testgo"  	 	db, err = sql.Open("mysql" , dsn)  	if  err != nil  { 		return  	} 	err = db.Ping()  	if  err != nil  { 		return  	} 	fmt.Println("连接数据库成功~" ) 	 	db.SetMaxIdleConns(10 ) 	return  } func  query (id int ) 	 	sqlStr := "select id,name,age from user where id=?;"  	 	rowObj := db.QueryRow(sqlStr, id)  	 	var  u1 user 	rowObj.Scan(&u1.id, &u1.name, &u1.age) 	 	fmt.Printf("u1:%#v\n" , u1) }   func  queryMore (n int ) 	 	sqlStr := "select id,name,age from user where id >?;"  	 	rows, err := db.Query(sqlStr, n) 	if  err != nil  { 		fmt.Printf("%s query failed,err:%v\n" , sqlStr, err) 		return  	} 	 	defer  rows.Close() 	 	for  rows.Next() { 		var  u1 user 		rows.Scan(&u1.id, &u1.name, &u1.age) 		fmt.Printf("u1:%#v\n" , u1) 	} }   func  main () 	err := initDB() 	if  err != nil  { 		fmt.Printf("init DB failed,err%v\n" , err) 	} 	 	query(3 ) 	 	queryMore(0 ) } 
结果实例如下:
#  2. GORM 连接数据库#  2.1 下载依赖1 go  get -u github.com/jinzhu/gorm
#  2.2 连接数据库1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package  mainimport  (	"fmt"  	"gorm.io/driver/mysql"  	"gorm.io/gorm"  ) func  main () 	 	url := "root:123456@tcp(localhost:3306)/testgo?charset=utf8&parseTime=True&loc=Local"  	 	_, err := gorm.Open(mysql.Open(url), &gorm.Config{}) 	if  err != nil  { 		fmt.Println("连接失败" ) 		return  	} else  { 		fmt.Println("连接成功" ) 	} } 
报错按照 GoLand 提示做就行,下载相应依赖
#  2.3 根据 go 创建表1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package  mainimport  (	"fmt"  	"gorm.io/driver/mysql"  	"gorm.io/gorm"  ) type  User struct  {	UserId   int  `gorm:"primary_key"`  	UserName string  	UserSex  string  } func  main () 	 	dsn := "root:123456@tcp(localhost:3306)/testgo?charset=utf8&parseTime=True&loc=Local"  	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) 	 	if  err != nil  { 		fmt.Println("数据库连接失败" ) 		return  	} 	 	 	db.AutoMigrate(&User{}) } 
#  2.4 插入数据1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package  mainimport  (	"fmt"  	"gorm.io/driver/mysql"  	"gorm.io/gorm"  ) type  User struct  {	UserId   int  `gorm:"primary_key"`  	UserName string  	UserSex  string  } func  main () 	 	dsn := "root:123456@tcp(localhost:3306)/testgo?charset=utf8&parseTime=True&loc=Local"  	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) 	 	if  err != nil  { 		fmt.Println("连接数据库失败" ) 		return  	} 	 	user := User{1 , "张三" , "男" } 	db.Create(user) } 
结果:
#  2.5 查询First&Take&Last
1 2 3 4 5 6 7 #First():通过主键进行升序排列,获取第一条数据 select * from table order by id limit 1 #Task():不通过列进行排序,直接获取第一条数据 select * from table limit 1 #Last():通过主键进行降序排列,获取第一条数据 select * from table order by id desc limit 1 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package  mainimport  (	"fmt"  	"gorm.io/driver/mysql"  	"gorm.io/gorm"  ) type  Books struct  {	 	BookID     int     `gorm:"column:bookID",gorm:"primary_key"`  	BookName   string  `gorm:"column:bookName"`  	BookCounts int     `gorm:"column:bookCounts"`  	Detail     string  `gorm:"column:detail"`  } func  main () 	 	url := "root:123456@tcp(localhost:3306)/testgo?charset=utf8&parseTime=True&loc=Local"  	 	db, err := gorm.Open(mysql.Open(url), &gorm.Config{}) 	if  err != nil  { 		fmt.Println("连接失败" ) 		return  	} 	 	 	 	 	 	 	 	 	 	var  book Books 	 	 	 	db.First(&book) 	 	 	 	 	 	 	db.Last(&book) 	fmt.Println(book) } 
#  2.6 多记录查询1 2 books :=[]Books{} db.Find(&books) 
#  2.7 条件查询1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37                     books := []Books{} db.Where("bookCounts between ? and ?" , 1 , 20 ).Find(&books) fmt.Println(books) 
#  2.8 删除数据1 2 3 4 5 6 	 	 	 	 	db.Where("bookName = ?" , "Linux" ).Delete(Books{}) 
#  2.9 查询1 2 3 4 5 6 7 8 9 	 	 	 	 	 	 	db.Model(Books{}).Where("bookName" , "MySQL" ).Updates(map [string ]interface {}{"BookCounts" : "33" , "Detail" : "MySQL太难了" }) 
#  三、gin-vue-admin 项目学习项目界面如下:
项目架构:
前端架构:
因为有前端 vue 基础,所以目前主要根据官方文档学后端 server 架构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ├── api │   └── v1 ├── config ├── core ├── docs ├── global ├── initialize │   └── internal ├── middleware ├── model │   ├── request │   └── response ├── packfile ├── resource │   ├── excel │   ├── page │   └── template ├── router ├── service ├── source └── utils     ├── timer     └── upload 
#  四、go 代码审计
目前在跟 Firebasky 师傅的 demo 进行学习
 
#  附录:go 新手向go 推荐项目 
go 学习视频 
Goweb 搭建 vue+go+gin+mysql+redis 的博客论坛 
基于 gin 框架和 gorm 的 web 开发实战 
#  参考文章https://blog.csdn.net/memory_qianxiao/article/details/109632778 
https://juejin.cn/post/7095205230983249934