1、变量和常量

package mainimport (    "fmt"    "strconv")// 入口函数func main() {    fmt.Println("hello world.")    // 变量,用于在程序中存储可变的值    // 1、命名只能有,字母、数字、下划线组成    //        只能以字母或下划线结尾    // 2、变量必须申明后应用,且申明后必须应用    // 变量申明    var name string         // 格局 : var 变量名称 变量类型    var name1, name2 string // 申明多个同类型的变量    var (                   // 申明多个不同类型的变量        name3 string        name4 int    )    // 变量赋值    name = "alice"    name1, name2 = "bob", "jan" // 给多个同类型的变量赋值    // 变量类型推导,无需指定变量类型,主动推导变量类型    // 只能写在函数体内    name5 := ""    name6, name7 := "", 1    fmt.Println("name=" + name)    fmt.Println("name1=" + name1)    fmt.Println("name2=" + name2)    fmt.Println("name3=" + name3)    fmt.Println("name4=" + strconv.Itoa(name4))    fmt.Println("name5=" + name5)    fmt.Println("name6=" + name6)    fmt.Println("name7=" + strconv.Itoa(name7))    // 常量,用于在程序中存储可变的值    // 1、命名只能有,字母、数字、下划线组成    //        只能以字母或下划线结尾    // 2、申明并且要赋值    const pi float32 = 3.14 // 申明单个常量    const (        n1 int = 1 // 指定常量类型        n2     = 2 // 主动类型推导    )    // iota    const (        m1 = iota // 初始值为0        m2        // 1        m3        // 2    )    fmt.Println("n1=" + strconv.Itoa(n1))    fmt.Println("n2=" + strconv.Itoa(n2))    fmt.Println("m1=" + strconv.Itoa(m1))    fmt.Println("m2=" + strconv.Itoa(m2))    fmt.Println("m3=" + strconv.Itoa(m3))} 

2、根本数据类型和转换

package mainimport (    "fmt"    "strconv")func main() {    // GO根本类型有,布尔类型、数值类型、字符串    // 布尔类型的标识符 : bool    // 取值范畴 : true(真),false(假),默认值是false    var isSunday bool // false    isSunday = true   // true    fmt.Println(isSunday)    // 数值类型,是用来示意数字的,例如整数、小数    // 整型、浮点型、复数    // 整型,用来存储整数的类型    // unit8、unit16、unit32、unit64、int8、int16、int32、int64    // unit、int、byte、rune、uintptr    // unit、int取值范畴,取决于所运行的操作系统位数    // byte 是unit8的别名    // rune int32的别名    // uintptr 无符号证书,用于存储指针    // 浮点数,艰深来讲,用于存储程序中带有小数点的值    // float32、float64    // 复数    // complex64、complex128    z := 1 + 2i    x := real(z)    y := imag(z)    fmt.Println(x, y)    // 字符串    // 一连串的字符组成的片段    var s1 string = "" // 定义单行字符串    var s2 string = `多行    字符串`    fmt.Println(s1, s2)    // 字符串的拼接    var s3 = "hello" + " " + "world."    fmt.Println(s3)    // 根本数据类型的转换    // 数值类型的转换    var n1 int16 = 1000    var n2 int32 = int32(n1)    // 将取值范畴小的类型转换为取值范畴大类型都是平安的    fmt.Println(n2)    // 将取值大的类型转换为取值小的类型都是有危险的,可能会截取    var n3 int8 = int8(n1)    fmt.Println(n3)    // int转换为字符串    var n4 int = 10    // Itoa,就是Int转换为ASCII    var n5 string = strconv.Itoa(n4)    fmt.Println(n5)    // 字符串转换为int类型    var s4 string = "100"    var n6, e = strconv.Atoi(s4)    if e != nil {        fmt.Println(e)    }    fmt.Println(n6)    // int64转换字符串    var n7 int64 = 10    fmt.Println(strconv.FormatInt(n7, 10))    // 字符串转换为int64    var s5 string = "100"    // 10 是 10进制,64 是 64位    var n8, e2 = strconv.ParseInt(s5, 10, 64)    if e != nil {        fmt.Println(e2)    }    fmt.Println(n8)}

3、操作符

package mainimport "fmt"func main() {    // 算数运算符 : + - * / %    var c = 5 % 3    fmt.Println(c)    // 自增 : ++    // 自减 : --    var c2 int    c2++    c2--    fmt.Println(c2)    // 关系运算符 : >、>=、<、<=、==    // 逻辑运算符 : &&、||、!    // 位运算符 : & | ^    // 移位运算符 : >> <<    // 赋值运算符 : +=、-=、*=、/=、%=    // 其余运算符 : & 返回变量存储地址 * 指针变量}

4、流程管制

package mainimport (    "fmt")func main() {    // 流程管制语句次要有三类 :    // 条件语句,if/else    var score = 78    if score >= 80 {        fmt.Println("优良")    } else if score >= 60 {        fmt.Println("及格")    } else {        fmt.Println("不及格")    }    // switch,从上到下,顺次匹配,一旦匹配后,就进行,否则都default    var grade = "A"    switch grade {    case "A":        fmt.Println("优良")    case "B":        fmt.Println("良好")    case "C":        fmt.Println("及格")    default:        fmt.Println("不及格")    }    // 循环语句for    // for 出事语句;是否进入循环的条件语句,布尔类型;每次循环语句完结    for i := 0; i <= 10; i++ {        fmt.Println(i)    }    var j = 10    for ; j >= 0; j-- { // 省略初始语句        fmt.Println(j)    }    var k = 10    for k >= 0 { // 省略初始和完结语句        fmt.Println(k)        k--    }    var l = 0    for { // 不带条件的构造        if l > 10 {            break // 终止for循环        }        if l == 4 {            l++            continue // 跳过本次循环        }        fmt.Println(l)        l++    }    // 循环嵌套    for i := 1; i < 10; i++ {        for j := 1; j <= i; j++ {            fmt.Printf("%d x %d = %d ", j, i, j*i)        }        fmt.Println("")    }} 

5、数组

package mainimport (    "fmt")func main() {    // 数组,是一组固定长度的、同类元素的汇合    // 固定长度,申明时指定长度,长度不可扭转    // 同类元素,数组中元素必须是同一类型    // 数组申明    var animals [3]string    // 数组赋值    // 赋值采纳索引(下标),索引从0开始,最初一个索引是长度-1    animals[0] = "cat" // 给第一个元素赋值    animals[1] = "cattle"    animals[2] = "sheep"    fmt.Println(animals)    // 申明并赋值    var numbers = [3]int{1, 2, 3}    fmt.Println(numbers)    // 申明时指定索引赋值    var numbers1 = [3]int{1: 2, 3}    fmt.Println(numbers1)    // 申明不指定长度,主动推算其长度    var cities = [...]string{"北京", "上海", "广州"}    fmt.Println(len(cities))    fmt.Println(cities)    // 数组遍历(循环)    for i := 0; i < len(cities); i++ {        fmt.Println(cities[i])    }    // 应用for range遍历    for index, city := range cities {        fmt.Println(index, city)    }    // 求一组数据的和    var nums = [5]int{1, 2, 3, 4, 5}    var result int    for _, num := range nums {        result += num    }    fmt.Println(result)} 

6、切片

package mainimport (    "fmt")func main() {    // 切片,是一组可变长度的,同类元素的汇合    // 与数组相比切片的长度是不固定的    // 能够追加元素,在追加时可能使切片的容量增大    // 切片的申明    var slice []int    // 切片在应用前必须初始化,未初始化的切片的值为nil    fmt.Println(slice == nil)    // 应用make()进行初始化    slice = make([]int, 3, 5)    fmt.Println(slice, len(slice), cap(slice))    // 初始化赋值    slice = []int{1, 2, 3, 4}    fmt.Println(slice, len(slice), cap(slice))    // 对数组进行切片    var a = []int{4, 5, 6, 7, 8}    // slice = a[起始索引:截止索引]    slice = a[1:3]    fmt.Println(slice)    // 切片的赋值,指定索引赋值    slice[1] = 100    fmt.Println(slice[1]) // 打印第二个元素的值    // 切片的追加    slice = append(slice, 200, 300, 400)    fmt.Println(slice)    // 批量追加    slice1 := []int{500, 600}    // slice = append(slice, 500, 600)    slice = append(slice, slice1...)    fmt.Println(slice)    // 对切片进行切片,截取    fmt.Println(slice[3:5])    // 切片的遍历,和数组的遍历办法一样    for i := 0; i < len(slice); i++ {        fmt.Println(i, slice[i])    }    for i, value := range slice {        fmt.Println(i, value)    }}

7、map

package mainimport (    "fmt")func main() {    // map(字典) 是一组无序的键值对(key-value)的汇合    // 申明map类型的变量    var country map[string]string    // 应用前必须初始化,未初始化的map的值为nil    fmt.Println(country == nil)    //country = make(map[string]string)    country = map[string]string{}    // map赋值    country["italy"] = "意大利"    fmt.Println(country)    fmt.Println(country["italy"])    // 判断key是否存在    val, ok := country["italy"]    fmt.Println(val, ok)    // 删除某个key-value    country["japan"] = "日本"    fmt.Println(country)    delete(country, "japan")    fmt.Println(country)    // map遍历    country["india"] = "印度"    country["france"] = "法国"    for key, val := range country {        fmt.Println(key, val)    }}

8、函数

package mainimport (    "fmt"    "math"    "time")/**func 函数名称(传入的参数和类型)(返回的参数和类型) {    函数体代码块}*/// 函数的定义// sum求两数之和func sum(x int, y int) int {    return x + y}// 函数能够没有传入参数,也能够没有返回参数// printTime 打印以后工夫func printTime() {    fmt.Println(time.Now())}const pi float64 = 3.14// 函数的多值返回,函数的返回值可有多个// calcCircle 计算园的周长和面积func calcCircle(r float64) (float64, float64) {    l := 2 * pi * r    s := pi * math.Pow(r, 2)    return l, s}func calcCircle2(r float64) (l float64, s float64) {    l = 2 * pi * r    s = pi * math.Pow(r, 2)    return}// 可变数量参数的函数,函数的参数的个数不固定// sumAny 计算任意个数的参数的和func sumAny(numbers ...int) int {    res := 0    for _, v := range numbers {        res += v    }    return res}// 匿名函数,就是没有命名的函数func anonymousFun() {    var x int = 1    var y int = 2    var sum = func(x, y int) int {        return x + y    }    fmt.Println(sum(x, y))}// 闭包 func(int, int) intfunc colsureFunc() func(int, int) int {    return func(x int, y int) int {        return x + y    }}func main() {    // 函数,是一段执行指定工作的代码块    // 是一段独立的,实现的,可重复使用的代码片段的定义    fmt.Println(sum(5, 3))    fmt.Println(calcCircle(10))    fmt.Println(calcCircle2(10))    fmt.Println(sumAny(1, 2, 3, 4, 5))    anonymousFun()    sum := colsureFunc()    fmt.Println(sum(1, 2))}

9、构造体

package mainimport "fmt"// 构造体是一些雷同或不同类型的元素形成的数据汇合// Go语言中没有其余语言中类(class)的概念// 但能够通过构造体实现面向对象编程// 构造体的定义/**type 类型名称 struct {    属性字段名称 属性类型}*/type Student struct {    Name  string    Age   int    City  string    Hobby string}// 构造体办法func (s Student) ShowIntroduction() string {    return fmt.Sprintf("%s, %d岁,来自%s,喜好是%s", s.Name, s.Age, s.City, s.Hobby)}func main() {    alice := Student{        Name:  "alice",        Age:   18,        City:  "洛杉矶",        Hobby: "打篮球",    }    // 构造体属性的拜访及赋值    fmt.Println(alice.Name)    alice.Age = 19    fmt.Println(alice.Age)    fmt.Println(alice.ShowIntroduction())}

10、接口

package mainimport (    "fmt"    "math")// 接口是一组办法定义的汇合,如果一个类型实现了这些办法,那么就实现了这个接口// 它是将所有具备共性的办法定义在一起,这些办法只有函数定义,没有具体实现type rect struct {    width  float64 // 宽    height float64 // 高}func (r rect) area() float64 {    return r.width * r.height}type circle struct {    radius float64 // radius 半径}func (c circle) area() float64 {    return math.Pi * c.radius * c.radius}type shape interface {    area() float64}// printArea 函数的参数能够是接口类型func printArea(s shape) {    fmt.Println(s.area())}func main() {    var shp shape    shp = rect{width: 2, height: 3}    fmt.Println(shp.area())    shp = circle{radius: 2}    fmt.Println(shp.area())    // 其实这里就是将子类传递给办法中的参数(参数是父类)    printArea(shp)    // 空接口    // 空接口是实现了0个办法的接口,空接口能够保留任意类型变量    var i interface{}    i = 1    fmt.Println(i)    i = "Hello World!"    fmt.Println(i)    // 阐明key能够是string类型,value是任意类型    var m = map[string]interface{}{        "v1": 1,        "v2": 2,    }    fmt.Println(m)    // 类型断言    var s interface{} = "str"    fmt.Println(s.(string))    v1, ok := s.(string)    fmt.Println(v1, ok)    v2, ok := s.(int)    fmt.Println(v2, ok)}

11、指针

package mainimport "fmt"func increment(i int) {    i++}func increment2(i *int) {    *i++}// 指针,是一种数据类型,用来示意数据的内存地址func main() {    // 申明一个int类型的变量,值为10    var a int = 10    // 通过&获取变量a的内存地址    fmt.Println(&a)    fmt.Printf("%T\n", &a)    // 申明一个int类型的指针变量    var b *int    b = &a    fmt.Println(b)    // 通过*获取指针指向的内存地址上的值    fmt.Println(*b)    // 批改指针地址的值    *b = 11    fmt.Println(*b)    fmt.Println(a)    var i int = 10    increment(i)    fmt.Println(i)    increment2(&i)    fmt.Println(i)}

12、异样

package mainimport (    "errors"    "fmt")// Go语言中的谬误,通常是将能够预期的谬误(error)作为返回值返回// 并非其余语言中的throw try/catch的形式// 面对于非预期的谬误,通常称之为异样,产生异样阐明程序中存在bug或者不可控的问题// 比方 数组越界,空指针等// 两数相除func div(a, b int) (int, error) {    if b == 0 {        return 0, errors.New("divisor cannot be zero.")    }    return a / b, nil}func div2(a, b int) (int, error) {    if b == 0 {        return 0, &DivError{}    }    return a / b, nil}func div3(a, b int) (int, error) {    defer func() { // 应用defer,该办法会最初执行        // 应用recover捕捉异样,保障程序不会解体退出,能失常继续执行        if err := recover(); err != nil {            fmt.Println("捕捉异样 :", err)        }    }()    if b == 0 {        panic("这里产生了异样")    }    return a / b, nil}// DivError 自定义谬误类型type DivError struct {}func (e *DivError) Error() string {    return "divisor cannot be zero"}func main() {    res, err := div(10, 0)    fmt.Println(res, err)    res2, err := div(10, 5)    fmt.Println(res2, err)    res3, err := div2(10, 0)    fmt.Println(res3, err)    res4, err := div3(10, 0)    fmt.Println(res4, err)} 

13、打包

go get -v github.com/go-sql-driver/mysqlpackage main// go mod tidy// go mod vendorimport (    "database/sql"    "fmt"    _ "github.com/go-sql-driver/mysql"    "log")func main() {    db, err := sql.Open("mysql", "root:root@123@tcp(127.0.0.1:3306)/journey")    if err != nil {        log.Fatal(err)    }    fmt.Println("connected.")    defer db.Close()}

14、gin

go get -v github.com/gin-gonic/gin@v1.9.0package mainimport "github.com/gin-gonic/gin"func main() {    r := gin.Default()    r.GET("/ping", func(c *gin.Context) {        c.JSON(200, gin.H{            "message": "pong",        })    })    r.GET("/test", func(context *gin.Context) {        context.JSON(200, gin.H{            "message": "test",        })    })    r.Run() // 监听并在 0.0.0.0:8080 上启动服务}

15、JSON和构造体相互转换

package mainimport (    "encoding/json"    "fmt")// Golang encoding/json包基于Struct类型的Tag个性,提供了JSON解析办法。这里正是反射的常见用法之一//包中最重要的两个函数如下://* Marshal(v interface{}) ([]byte, error) : 将 Go 数据类型软换为 JSON 格局数据//* Unmarshal(data []byte, v interface{}):将 JSON 格局数据转换为 Go 数据类型//针对 Tag 的写法,encoding/json 作了如下约定://json:"Foo" : Marshal 时将构造体该字段名以 “Foo” 名输入,Unmarshal 时将 JSON 相应字段赋值给构造体字段//json:"-": 无论 Marshal 和 Unmarshal 都疏忽该字段//json:",omitempty": 仅用于 Marshal,如果构造体该字段为空,则疏忽该字段。留神后面的逗号要保留//json:"Foo,omitempty": 组合写法,含意同上// 对于 omitempty,要留神它会屏蔽所有的初始值和空值。比方,整型,即使赋值为 0,其也不会被转换为 JSON 字符串。 有时,你心愿构造体存储的是某个状态,而状态中正好有个值为 “零”,这时就要小心了func main() {    str := `{"ServerName": "Shanghai_VPN", "ServerAddr": "127.0.0.1", "ServerOwner": "Rainbow", "other": "You can see me!"}`    var s Server    // 其实就是把字符串转换为byte数组 []byte(str)    json.Unmarshal([]byte(str), &s)    fmt.Printf("s.ServerName: %s\n", s.ServerName)    fmt.Printf("s.ServerIP: %s\n", s.ServerIP)    fmt.Printf("s.ServerOwner: %s\n", s.ServerOwner)    fmt.Printf("s.other: %s\n", s.Other)    jsonStr, _ := json.Marshal(s)    fmt.Printf("Marshal: %s", jsonStr)}
inline这个属性,应该是默认的,为什么这么说,这个属性用作嵌套构造体内,打消嵌套构造体的层级关系,将其转为一个层级比方 :type TestField struct {    Key string `json:"key"`}//type TopField struct {//    T TestField `json:",omitempty"`//    TestA     string `json:"test_a"`//    TestB     string `json:"test_b"`//}type TopField struct {    TestField `json:",omitempty,inline"`    TestA     string `json:"test_a"`    TestB     string `json:"test_b"`}func main() {    one := TopField{        TestField: TestField{            Key: "12321",        },        TestA: "a",        TestB: "b",    }    marshal, _ := json.Marshal(one)    fmt.Println(string(marshal))}// {"key":"12321","test_a":"a","test_b":"b"}