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、mappackage 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、gingo 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"}