Go(一)基础入门

Go(一)基础入门
本文在:csdn、公众号同步更新。

本文首发于CSDN,作者:lomtom

原文链接:https://blog.csdn.net/qq_41929184/article/details/119995270 🔗

个人网站:https://lomtom.top 🔗,个人公众号:博思奥园 🔗,同步更新。

你的支持就是我最大的动力。

Go系列:

  1. Go(一)基础入门
  2. Go(二)结构体
  3. Go(三)Go配置文件
  4. Go(四)Redis还不会使用?
  5. Go(五)Go不知道怎么用Gorm?
  6. Go(六)来来来,教你怎么远程调用
  7. Go(七)你说你不会并发?
  8. Go(八)还不知道函数式选项模式?

go是非常年轻的一门语言,它的主要目标是“兼具Python 等动态语言的开发速度和C/C++等编译型语言的性能与安全性”

目前Go语言已经⼴泛应用于人工智能、云计算开发、容器虚拟化、⼤数据开发、数据分析及科学计算、运维开发、爬虫开发、游戏开发等领域。

go代码结构

Go语言结构(组成部分):

    包声明
    引入包
    函数
    变量
    语句 & 表达式
    注释

例如hello.go

package main


//标准输出库
import "fmt"

//主函数:包名需要为main才可以运行
func main() {
	//输出
	fmt.Println("Hello World")
}

  1. 第一行代码 package main 定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。

  2. 下一行 import “fmt” 告诉 Go 编译器这个程序需要使用 fmt 包(的函数,或其他元素),fmt 包实现了格式化 IO(输入/输出)的函数。

  3. 下一行 func main() 是程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。

  4. 下一行 //或 // 是注释,在程序执行时将被忽略。

    单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。

    多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段。

  5. 下一行 fmt.Println(…) 可以将字符串输出到控制台,并在最后自动增加换行字符 \n。

    使用 fmt.Print(“hello, world\n”) 可以得到相同的结果。

    Print 和 Println 这两个函数也支持使用变量,如:fmt.Println(arr)。如果没有特别指定,它们会以默认的打印格式将变量 arr 输出到控制台。

  6. 当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。

go语言区别于JAVA

  1. 当大括号的前半部分没有和函数名在同一行时,程序会报错

    错误示例:

    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 {
    
  2. Go语言每行结尾可以不加分号;

  3. 变量声明

    • 声明变量的一般形式是使用 var 关键字:例如我想声明一个int类型的变量a,那么则是: var a int

      即:var关键字 + 变量名 + 变量类型

    • Go也支持多个变量同时声明,也可以不赋初始值(为变量的默认值),例如var b, c int = 1, 2var 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
      }
      
  4. Go不支持三目运算符

  5. Go的返回类型在函数小括号后面,大括号前面,支持返回多个值 例如:

    package main
    
    /* 函数返回两个数的和 */
    func sum(num1, num2 int) int {
         return num1 + num2
    }
    
    func swap(x, y string) (string, string) {
       return y, x
    }
    
  6. Go中的结构体跨包调用,属性首字母必须大写否则会爆unexported field错误

  7. Go不支持隐式的类型转换

  8. Go中实现异步执行


// 异步执行
go task2.SendMail()
  1. 睡眠
time.Sleep(time.Duration(2)*time.Second)
  1. Go不支持互相导包 如果package A中已经导入package B,而本package中又导入package B

    或者 package A依赖package B,同时 package B 依赖package A

    这样就会在编译时报 “import cycle not allowed”。

    如何避免重复导入包的问题,就需要在设计时规划好包。

gin框架使用

  1. 简单的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))
}

  1. gin集成swag

    1. main.go必须和其他包处于同一文件夹下,否则接口识别不出来。
    2. 集成
      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#/
      
      不过,在我的感受,swagger在go语言中并不是特别的好使,每次写一个新的接口都需要写一大堆swagger的注释,不会像java一样自动识别。
  2. 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)
    
  3. 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())
lomtom

标题:Go(一)基础入门

作者:lomtom

链接:https://lomtom.cn/e3f06601