共计 10496 个字符,预计需要花费 27 分钟才能阅读完成。
1、变量和常量
package main | |
import ( | |
"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 main | |
import ( | |
"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 main | |
import "fmt" | |
func main() { | |
// 算数运算符 : + - * / % | |
var c = 5 % 3 | |
fmt.Println(c) | |
// 自增 : ++ | |
// 自减 : -- | |
var c2 int | |
c2++ | |
c2-- | |
fmt.Println(c2) | |
// 关系运算符 : >、>=、<、<=、== | |
// 逻辑运算符 : &&、||、! | |
// 位运算符 : & | ^ | |
// 移位运算符 : >> << | |
// 赋值运算符 : +=、-=、*=、/=、%= | |
// 其余运算符 : & 返回变量存储地址 * 指针变量 | |
} |
4、流程管制
package main | |
import ("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 main | |
import ("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 main | |
import ("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 main | |
import ("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 main | |
import ( | |
"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) int | |
func 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 main | |
import "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 main | |
import ( | |
"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 main | |
import "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 main | |
import ( | |
"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/mysql | |
package main | |
// go mod tidy | |
// go mod vendor | |
import ( | |
"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.0 | |
package main | |
import "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 main | |
import ( | |
"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"} |
正文完