Go(一)基础入门

Go(一)基础入门

本文在:csdn、公众号同步更新。

本文首发于CSDN,作者:lomtom

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

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

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

Go系列:

  1. Go(一)基础入门
  2. Go(二)结构体

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

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

go代码结构

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

1
2
3
4
5
6
包声明
引入包
函数
变量
语句 & 表达式
注释

例如hello.go

1
2
3
4
5
6
7
8
9
10
11
12
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. 当大括号的前半部分没有和函数名在同一行时,程序会报错

    错误示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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在函数内使用var:=声明过的变量必须被使用,否则会报错:Unused variable 'xxx'

    • Go与C一样,存在地址传递和指传递,即可以使用*&,对于 int、float、bool 和 string等值引用,需要进行值交换则必须可以使用地址进行传递

      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
      76
         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`赋值后(为常量),其值不可改变,再次赋值会报错。

      注:常量可用于枚举:
      ```go
      const (
      Unknown = 0
      Female = 1
      Male = 2
      )

      - Go也支持为不同的类型同时赋值,例如`const a, b, c = 1, false, "str"`
      - iota,特殊常量,可以认为是一个可以被编译器修改的常量。

      iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。

      ```go
      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的返回类型在函数小括号后面,大括号前面,支持返回多个值,接收多个返回值时,申明多个变量进行接收即可。
    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    package main

    /* 函数返回两个数的和 */
    func sum(num1, num2 int) int {
    return num1 + num2
    }

    func swap(x, y string) (string, string) {
    return y, x
    }

    func main(){
    s1 := "s1"
    s2 := "s2"
    // 定义两个变量接收swap函数的返回值
    s3,s4 := swap(s1,s2)
    fmt.Println(s3)
    fmt.Println(s4)
    }
  6. Go中的结构体跨包调用,属性首字母必须大写否则会爆unexported field错误

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

  8. Go中实现异步执行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 异步执行task2.SendMail方法
    go task2.SendMail()

    // 异步执行代码块

    go func() {
    fmt.Println("hello world...")
    fmt.Println("支持一下吧...")
    }()
  9. 睡眠

    1
    2
    3
    4
    5
    6
    7
    import (
    "time"
    )

    func main(){
    time.Sleep(time.Duration(2)*time.Second)
    }
  10. Go不支持互相导包
    如果package A中已经导入package B,而本package中又导入package B

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

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

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

gin框架使用

  1. 简单的http请求

    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
    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))
    }

  2. gin集成swag

    1. main.go必须和其他包处于同一文件夹下,否则接口识别不出来。
    2. 集成
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
       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一样自动识别。
  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
    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
    }

    其次,对结果进行统一管理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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") //参数错误
    )

    使用

    1
    c.JSON(result.Status, result.OK)
  4. Gin的body的参数只能获取一次,若想多次获取,需要在获取之后重新对body进行赋值。

    1
    2
    3
    4
    5
    6
    7
    8
    generalMessageByTemplate := make(map[string]interface{})
    generalMessageByTemplate["receiver"] = []string{sendVerifyCode.Phone}
    generalMessageByTemplate["templateCode"] = templateCode
    generalMessageByTemplate["msg"] = param
    // 转为[]byte
    marshal, _ := json.Marshal(generalMessageByTemplate)
    // 重新赋值
    s.Context.Request.Body = ioutil.NopCloser(bytes.NewBuffer(marshal))

模板设置

1、标准输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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、输出到变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
模板输出
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())

Go(一)基础入门

http://example.com/e3f06601.html

作者

lomtom

发布于

2021-09-24

更新于

2021-09-26

许可协议


评论