Go(一)基础入门
- September 24, 2021
本文首发于CSDN,作者:lomtom
原文链接:https://blog.csdn.net/qq_41929184/article/details/119995270 🔗
个人网站:https://lomtom.top 🔗,个人公众号:博思奥园 🔗,同步更新。
你的支持就是我最大的动力。
Go系列:
- Go(一)基础入门
- Go(二)结构体
- Go(三)Go配置文件
- Go(四)Redis还不会使用?
- Go(五)Go不知道怎么用Gorm?
- Go(六)来来来,教你怎么远程调用
- Go(七)你说你不会并发?
- Go(八)还不知道函数式选项模式?
go是非常年轻的一门语言,它的主要目标是“兼具Python 等动态语言的开发速度和C/C++等编译型语言的性能与安全性”
目前Go语言已经⼴泛应用于人工智能、云计算开发、容器虚拟化、⼤数据开发、数据分析及科学计算、运维开发、爬虫开发、游戏开发等领域。
go代码结构
Go语言结构(组成部分):
包声明
引入包
函数
变量
语句 & 表达式
注释
例如hello.go
package main
//标准输出库
import "fmt"
//主函数:包名需要为main才可以运行
func main() {
//输出
fmt.Println("Hello World")
}
-
第一行代码 package main 定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
-
下一行 import “fmt” 告诉 Go 编译器这个程序需要使用 fmt 包(的函数,或其他元素),fmt 包实现了格式化 IO(输入/输出)的函数。
-
下一行 func main() 是程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。
-
下一行 /…/或 // 是注释,在程序执行时将被忽略。
单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。
多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段。
-
下一行 fmt.Println(…) 可以将字符串输出到控制台,并在最后自动增加换行字符 \n。
使用 fmt.Print(“hello, world\n”) 可以得到相同的结果。
Print 和 Println 这两个函数也支持使用变量,如:fmt.Println(arr)。如果没有特别指定,它们会以默认的打印格式将变量 arr 输出到控制台。
-
当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。
go语言区别于JAVA
-
当大括号的前半部分没有和函数名在同一行时,程序会报错
错误示例:
package main //标准输出库 import "fmt" //主函数:包名需要为main才可以运行 func main() { //输出 fmt.Println("Hello World") } 报错: # command-line-arguments .\print.go:8:6: missing function body .\print.go:9:1: syntax error: unexpected semicolon or newline before {
-
Go语言每行结尾可以不加分号
;
-
变量声明
-
声明变量的一般形式是使用 var 关键字:例如我想声明一个
int
类型的变量a,那么则是:var a int
即:
var关键字 + 变量名 + 变量类型
-
Go也支持多个变量同时声明,也可以不赋初始值(为变量的默认值),例如
var b, c int = 1, 2
或var b, c int
-
Go也有简化关键字var的写法,例如
var a int = 1
可以省略成a := 1
-
Go声明过的变量必须被使用,否则会报错, Go与C一样,存在地址传递和指传递,即可以使用
*
和&
,对于int、float、bool 和 string
等值引用,就可以使用地址进行值交换package main //标准输出库 import "fmt" func swap(a, b int) { a, b = b, a } func swap1(a, b *int) { *a, *b = *b, *a } //主函数:包名需要为main才可以运行 func main() { //输出 fmt.Println("Hello World") a, b := 1, 2 //无法交换 swap(a, b) fmt.Println("哈哈", a, b) //可以交换 swap1(&a, &b) fmt.Println("哈哈", a, b) //可以交换 a, b = b, a fmt.Println("哈哈", a, b) } 输出为: Hello World 哈哈 1 2 哈哈 2 1 哈哈 1 2
-
使用
const
赋值后(为常量),其值不可改变,再次赋值会报错。注:常量可用于枚举:
const ( Unknown = 0 Female = 1 Male = 2 )
-
Go也支持为不同的类型同时赋值,例如
const a, b, c = 1, false, "str"
-
iota,特殊常量,可以认为是一个可以被编译器修改的常量。
iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。
package main import "fmt" func main() { const ( a = iota //0 b //1 c //2 d = "ha" //独立值,iota += 1 e //"ha" iota += 1 f = 100 //iota +=1 g //100 iota +=1 h = iota //7,恢复计数 i //8 ) fmt.Println(a,b,c,d,e,f,g,h,i) //输出 0 1 2 ha ha 100 100 7 8 }
-
-
Go不支持三目运算符
-
Go的返回类型在函数小括号后面,大括号前面,支持返回多个值 例如:
package main /* 函数返回两个数的和 */ func sum(num1, num2 int) int { return num1 + num2 } func swap(x, y string) (string, string) { return y, x }
-
Go中的结构体跨包调用,属性首字母必须大写否则会爆
unexported field
错误 -
Go不支持隐式的类型转换
-
Go中实现异步执行
// 异步执行
go task2.SendMail()
- 睡眠
time.Sleep(time.Duration(2)*time.Second)
-
Go不支持互相导包 如果package A中已经导入package B,而本package中又导入package B
或者 package A依赖package B,同时 package B 依赖package A
这样就会在编译时报 “import cycle not allowed”。
如何避免重复导入包的问题,就需要在设计时规划好包。
gin框架使用
- 简单的http请求
package main
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
func main() {
// 1.创建路由
r := gin.Default()
// 2.绑定路由规则,执行的函数
// gin.Context,封装了request和response
r.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "hello World!")
})
r.GET("/user/:name/*action", func(c *gin.Context) {
name := c.Param("name")
action := c.Param("action")
action = strings.Trim(action,"/")
c.String(http.StatusOK,name + " is a " + action)
})
r.GET("/url", func(c *gin.Context) {
name := c.DefaultQuery("name","小葛")
c.String(http.StatusOK,fmt.Sprintf("hello %s",name))
})
r.POST("/form", func(c *gin.Context) {
types := c.DefaultPostForm("type","post")
username := c.PostForm("username")
password := c.PostForm("password")
c.String(http.StatusOK,fmt.Sprintf("username = %s , password = %s , types = %s",username,password,types))
})
// 分组使用
v1 := r.Group("/v1")
{
v1.GET("/api1",api1)
v1.GET("/api2",api2)
}
v2 := r.Group("/v2")
{
v2.POST("/api1",api1)
v2.POST("/api2",api2)
}
// 3.监听端口,默认在8000
// Run("里面不指定端口号默认为8000")
r.Run(":8000")
}
func api1(c *gin.Context) {
name := c.DefaultQuery("name", "小欧")
c.String(200, fmt.Sprintf("hello %s", name))
}
func api2(c *gin.Context) {
name := c.DefaultQuery("name", "小欧")
c.String(200, fmt.Sprintf("hello %s", name))
}
-
gin集成swag
- main.go必须和其他包处于同一文件夹下,否则接口识别不出来。
- 集成
不过,在我的感受,swagger在go语言中并不是特别的好使,每次写一个新的接口都需要写一大堆swagger的注释,不会像java一样自动识别。1. 引入依赖 import ( _ "demo_go/src/docs" "github.com/gin-gonic/gin" ginSwagger "github.com/swaggo/gin-swagger" "github.com/swaggo/gin-swagger/swaggerFiles" ) swagger func SetupRouter() *gin.Engine { r := gin.Default() r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) loadUser(r) loadIndex(r) return r } 2. 在main.go的同目录下运行swag init,就会生成一个docs文件夹下,将第一步中 demo_go/src/docs 替换为 docs 文件夹的路径 3.访问 http://localhost:8000/swagger/index.html#/
-
Go 返回统一封装 首先进行响应结果的封装
package result type Result struct { Status int `json:"status"` //状态码 ResMsg string `json:"resMsg"` //状态描述 Data map[string]interface{} `json:"data"` //数据 } /* 统一返回接口 */ func result(status int, msg string) *Result { return &Result{ Status: status, ResMsg: msg, Data: make(map[string]interface{},0), } } //WithMsg 设置提示信息 func (r *Result) WithMsg(msg string) *Result { r.ResMsg = msg return r } //WithData 设置数据 func (r *Result) WithData(key string,data interface{}) *Result { r.Data[key] = data return r }
其次,对结果进行统一管理
package result var ( OK = result(200,"ok") // 通用成功 ERROR = result(500,"error") // 通用失败 UserNotFind = result(404,"user not find") //未找到用户 RegisterFailed = result(400,"user register failed") //注册失败 ParameterError = result(500,"parameter error") //参数错误 )
使用
c.JSON(result.Status, result.OK)
-
Gin的body的参数只能获取一次
模板设置
1、标准输出
https://blog.csdn.net/liumiaocn/article/details/54882507
type person struct {
Id int
Name string
Country string
}
person1 := person{Id: 1001, Name: "lomtom", Country: "China"}
tmpl := template.New("tmpl1")
registerContent1 :=" 尊敬的{{.Name}}您好:\n" +"\n"+
" 您已被设置为该主账户的消息接收人。若同意接收该账户下的消息通知,请单击下列链接。\n" +" 如果单击链接没有反应,请复制到浏览器中。\n" +
"\n" +
" 致敬!\n\n" +
"LStack团队"
tmpl.Parse(registerContent1)
tmpl.Execute(os.Stdout, person1)
2、输出到变量
模板输出
https://blog.csdn.net/changzhe1253/article/details/100963119
person := make(map[string]string)
person["Name"] = "lomtom"
tmpl := template.New("tmpl1")
registerContent :="尊敬的{{.Name}}您好:\n" +
"\t您已被设置为该主账户的消息接收人。若同意接收该账户下的消息通知,请单击下列链接。\n" +" 如果单击链接没有反应,请复制到浏览器中。\n" +
" 致敬!\n\n" +
"LStack团队"
tmpl.Parse(registerContent)
var str bytes.Buffer
tmpl.Execute(&str, person)
fmt.Println(str.String())