{"id":16558017,"url":"https://github.com/typ0520/golang-learning","last_synced_at":"2026-04-19T01:34:48.415Z","repository":{"id":206005890,"uuid":"313899179","full_name":"typ0520/golang-learning","owner":"typ0520","description":null,"archived":false,"fork":false,"pushed_at":"2021-02-24T09:39:58.000Z","size":103,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-04T23:42:00.588Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/typ0520.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-11-18T10:27:53.000Z","updated_at":"2021-03-30T09:42:59.000Z","dependencies_parsed_at":"2023-11-07T15:03:43.679Z","dependency_job_id":null,"html_url":"https://github.com/typ0520/golang-learning","commit_stats":null,"previous_names":["typ0520/golang-learning"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/typ0520/golang-learning","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typ0520%2Fgolang-learning","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typ0520%2Fgolang-learning/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typ0520%2Fgolang-learning/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typ0520%2Fgolang-learning/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/typ0520","download_url":"https://codeload.github.com/typ0520/golang-learning/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typ0520%2Fgolang-learning/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31991715,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"ssl_error","status_checked_at":"2026-04-18T20:23:29.375Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T20:09:20.111Z","updated_at":"2026-04-19T01:34:48.364Z","avatar_url":"https://github.com/typ0520.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"### 关键字\n```\nGo语言中有25个关键字：\n\n\nbreak        default      func         interface    select\ncase         defer        go           map          struct\nchan         else         goto         package      switch\nconst        fallthrough  if           range        type\ncontinue     for          import       return       var\n\n此外，Go语言中还有37个保留字。\n\nConstants:    true  false  iota  nil\n\nTypes:    int  int8  int16  int32  int64  \n            uint  uint8  uint16  uint32  uint64  uintptr\n            float32  float64  complex128  complex64\n            bool  byte  rune  string  error\n\nFunctions:   make  len  cap  new  append  copy  close  delete\n                complex  real  imag\n                panic  recover\n\n```\n\n### 变量\n\n- 变量声明\n\n```\nvar 变量名 类型 = 表达式\n\nvar name string = \"Q1mi\"\nvar age int = 18\nvar name, age = \"Q1mi\", 20\n\n在函数内部，可以使用更简略的 := 方式声明并初始化变量。\nm := 200 // 此处声明局部变量m\n```\n\n- 批量声明\n```\nvar (\n    a string\n    b int\n    c bool\n    d float32\n)\n```\n\n- 常量\n```\nconst pi = 3.1415\nconst e = 2.7182\n\nconst (\n    pi = 3.1415\n    e = 2.7182\n)\n\n常量n1、n2、n3的值都是100\nconst (\n    n1 = 100\n    n2\n    n3\n)\n```\n\n- iota\n\ngo语言的常量计数器，只能在常量的表达式中使用\n```\nconst (\n    n1 = iota //0\n    n2        //1\n    n3        //2\n    n4        //3\n)\n\nconst (\n    n1 = iota //0\n    n2        //1\n    _\n    n4        //3\n)\n\nconst (\n    n1 = iota //0\n    n2 = 100  //100\n    n3 = iota //2\n    n4        //3\n)\nconst n5 = iota //0\n\n\nconst (\n    _  = iota\n    KB = 1 \u003c\u003c (10 * iota)\n    MB = 1 \u003c\u003c (10 * iota)\n    GB = 1 \u003c\u003c (10 * iota)\n    TB = 1 \u003c\u003c (10 * iota)\n    PB = 1 \u003c\u003c (10 * iota)\n)\n```\n\n### 基本数据类型\n\n- 整型\n```\nuint8\t无符号 8位整型 (0 到 255)\nuint16\t无符号 16位整型 (0 到 65535)\nuint32\t无符号 32位整型 (0 到 4294967295)\nuint64\t无符号 64位整型 (0 到 18446744073709551615)\nint8\t有符号 8位整型 (-128 到 127)\nint16\t有符号 16位整型 (-32768 到 32767)\nint32\t有符号 32位整型 (-2147483648 到 2147483647)\nint64\t有符号 64位整型 (-9223372036854775808 到 9223372036854775807)\n\nuint\t32位操作系统上就是uint32，64位操作系统上就是uint64\nint\t32位操作系统上就是int32，64位操作系统上就是int64\nuintptr\t无符号整型，用于存放一个指针\n```\n\n- 浮点型\n\nfloat32、float64\n\n```\nfloat32 的浮点数的最大范围约为 3.4e38，可以使用常量定义：math.MaxFloat32。 float64 的浮点数的最大范围约为 1.8e308，可以使用一个常量定义：math.MaxFloat64\n```\n\n- 布尔值\n\ntrue/false\n\n- 字符串转义符\n\n```\n\\r\t回车符（返回行首）\n\\n\t换行符（直接跳到下一行的同列位置）\n\\t\t制表符\n\\'\t单引号\n\\\"\t双引号\n\\\\\t反斜杠\n```\n\n- 字符串\n```\n多行字符串\ns1 := `第一行\n第二行\n第三行\n`\nfmt.Println(s1)\n\n字符串的常用操作\nlen(str)\t求长度\n+或fmt.Sprintf\t拼接字符串\nstrings.Split\t分割\nstrings.contains\t判断是否包含\nstrings.HasPrefix,strings.HasSuffix\t前缀/后缀判断\nstrings.Index(),strings.LastIndex()\t子串出现的位置\nstrings.Join(a[]string, sep string)\tjoin操作\n```\n\n### 类型转换\n\nT(表达式)\n```\nvar a, b = 3, 4\nvar c int\n// math.Sqrt()接收的参数是float64类型，需要强制转换\nc = int(math.Sqrt(float64(a*a + b*b)))\nfmt.Println(c)\n```\n\n### if条件判断特殊写法\n\n```\nfunc ifDemo2() {\n\tif score := 65; score \u003e= 90 {\n\t\tfmt.Println(\"A\")\n\t} else if score \u003e 75 {\n\t\tfmt.Println(\"B\")\n\t} else {\n\t\tfmt.Println(\"C\")\n\t}\n}\n```\n\n### 循环for\nbreak、goto、return、panic语句强制退出循环\n\n```\nfor i := 0; i \u003c 10; i++ {\n    fmt.Println(i)\n}\n\n无限循环\nfor {\n    循环体语句\n}\n```\n\n### 数组\nvar 数组变量名 [元素数量]T\n\n```\n// 定义一个长度为3元素类型为int的数组a\nvar a [3]int\n\nvar a [3]int\nvar b [4]int\na = b //不可以这样做，因为此时a和b是不同的类型\n\n//编译器根据初始值的个数自行推断数组的长度\nvar numArray = [...]int{1, 2}\n\na := [...]int{1: 1, 3: 5}\nfmt.Println(a)                  // [0 1 0 5]\n\n//使用指定的初始值完成初始化\nvar cityArray = [3]string{\"北京\", \"上海\", \"深圳\"} \n\nvar a = [...]string{\"北京\", \"上海\", \"深圳\"}\n// 方法1：for循环遍历\nfor i := 0; i \u003c len(a); i++ {\n    fmt.Println(a[i])\n}\n\n// 方法2：for range遍历\nfor index, value := range a {\n    fmt.Println(index, value)\n}\n\na := [3][2]string{\n\t\t{\"北京\", \"上海\"},\n\t\t{\"广州\", \"深圳\"},\n\t\t{\"成都\", \"重庆\"},\n\t}\n\tfmt.Println(a) //[[北京 上海] [广州 深圳] [成都 重庆]]\n\tfmt.Println(a[2][1]) //支持索引取值:重庆\n}\n\n定长的是值类型、非定长是引用类型\nfunc main() {\n\ta := [3]int{10, 20, 30}\n\tmodifyArray(a)\n\tfmt.Println(a)//[10 20 30]\n}\n\nfunc modifyArray(x [3]int) {\n\tx[0] = 100\n}\n\nfunc main() {\n\ta := []int{10, 20, 30}\n\tmodifyArray(a)\n\tfmt.Println(a)//[100 20 30]\n}\n\nfunc modifyArray(x []int) {\n\tx[0] = 100\n}\n```\n\n### 切片\n\nmake([]T, size, cap)\n\n```\na := make([]int, 2, 10)\nfmt.Println(a)      //[0 0]\nfmt.Println(len(a)) //2\nfmt.Println(cap(a)) //10\n\nvar a []string              //声明一个字符串切片\n```\n\n### map\n\nmap是一种无序的基于key-value的数据结构，Go语言中的map是引用类型\n\n```\nscoreMap := make(map[string]int, 8)\nscoreMap[\"张三\"] = 90\nscoreMap[\"小明\"] = 100\nfmt.Println(scoreMap)\nfmt.Println(scoreMap[\"小明\"])\nfmt.Printf(\"type of a:%T\\n\", scoreMap)\n\n//判断key是否存在\nv, ok := scoreMap[\"张三\"]\nif ok {\n    fmt.Println(v)\n} else {\n    fmt.Println(\"not found\")\n}\n\n//遍历\nfor k, v := range scoreMap {\n    fmt.Println(k)\n    fmt.Println(v)\n}\nfor k := range scoreMap {\n    fmt.Println(k)\n}\nfor _, v := range scoreMap {\n    fmt.Println(v)\n}\n\n//删除键值对\ndelete(scoreMap, \"张三\")\n\nfor k, v := range scoreMap {\n    fmt.Println(k)\n    fmt.Println(v)\n}\n```\n\n### 函数\n\n```\nfunc 函数名(参数)(返回值){\n    函数体\n}\n```\n\n```\nfunc intSum(x int, y int) int {\n\treturn x + y\n}\n\n//可变参数\nfunc intSum2(x ...int) int {\n\tfmt.Println(x) //x是一个切片\n\tsum := 0\n\tfor _, v := range x {\n\t\tsum = sum + v\n\t}\n\treturn sum\n}\n\n//定义函数类型\ntype calculation func(int, int) int\nfunc add(x, y int) int {\n\treturn x + y\n}\nfunc sub(x, y int) int {\n\treturn x - y\n}\nvar c calculation\nc = add\n\n\n//匿名函数\n// 将匿名函数保存到变量\nadd := func(x, y int) {\n    fmt.Println(x + y)\n}\nadd(10, 20) // 通过变量调用匿名函数\n\n//自执行函数：匿名函数定义完加()直接执行\nfunc(x, y int) {\n    fmt.Println(x + y)\n}(10, 20)\n```\n\n### defer语句\n\n```\nfmt.Println(\"start\")\ndefer fmt.Println(1)\ndefer fmt.Println(2)\ndefer fmt.Println(3)\nfmt.Println(\"end\")\n\nstart\nend\n3\n2\n1\n```\n\n```\nfunc calc(index string, a, b int) int {\n\tret := a + b\n\tfmt.Println(index, a, b, ret)\n\treturn ret\n}\n\nfunc main() {\n\tx := 1\n\ty := 2\n\tdefer calc(\"AA\", x, calc(\"A\", x, y))\n\tx = 10\n\tdefer calc(\"BB\", x, calc(\"B\", x, y))\n\ty = 20\n}\n\nA 1 2 3\nB 10 2 12\nBB 10 12 22\nAA 1 3 4\n```\n\n### 内置函数介绍\n\n```\nclose\t主要用来关闭channel\nlen\t用来求长度，比如string、array、slice、map、channel\nnew\t用来分配内存，主要用来分配值类型，比如int、struct。返回的是指针\nmake\t用来分配内存，主要用来分配引用类型，比如chan、map、slice\nappend\t用来追加元素到数组、slice中\npanic和recover\t用来做错误处理\n```\n\n### 指针\n\n```\n//指针取值\na := 10\nb := \u0026a // 取变量a的地址，将指针保存到b中\nfmt.Printf(\"type of b:%T\\n\", b)\nc := *b // 指针取值（根据指针去内存取值）\nfmt.Printf(\"type of c:%T\\n\", c)\nfmt.Printf(\"value of c:%v\\n\", c)\n\ntype of b:*int\ntype of c:int\nvalue of c:10\n\nmake只用于slice、map以及channel的初始化，返回的还是这三个引用类型本身；\n而new用于类型的内存分配，并且内存对应的值为类型零值，返回的是指向类型的指针。\n```\n\n### 结构体\n\n```\ntype 类型名 struct {\n    字段名 字段类型\n    字段名 字段类型\n    …\n}\n```\n\n```\n//类型定义\ntype NewInt int\n//类型别名\ntype MyInt = int\n\nfunc structDemo() {\n\tvar a NewInt\n\tvar b MyInt\n    fmt.Printf(\"type of a:%T\\n\", a) //type of a:main.NewInt\n\tfmt.Printf(\"type of b:%T\\n\", b) //type of b:int\n}\n```\n\n```\ntype person struct {\n    name string\n    city string\n    age int8\n}\n\ntype person2 struct {\n    name, city string\n    age int8\n}\n\nvar p1 person\np1.name = \"dp\"\np1.city = \"shanghai\"\np1.age = 18\nfmt.Printf(\"p1=%v\\n\", p1)\nfmt.Printf(\"p1=%#v\\n\", p1)\nfmt.Printf(\"p1: %T\\n\", \u0026p1)//p1: *main.person\n\n//指针类型结构体\nvar p2 = new(person)\np2.name = \"dp2\"\np2.city = \"shanghai2\"\nfmt.Printf(\"p2: %T\\n\", p2)//p2: *main.person\n\np3 := \u0026person{}\nfmt.Printf(\"%T\\n\", p3)     //*main.person\nfmt.Printf(\"p3=%#v\\n\", p3) //p3=\u0026main.person{name:\"\", city:\"\", age:0}\np3.name = \"七米\"\np3.age = 30\np3.city = \"成都\"\nfmt.Printf(\"p3=%#v\\n\", p3) //p3=\u0026main.person{name:\"七米\", city:\"成都\", age:30}\n\nvar p4 person\nfmt.Printf(\"p4=%#v\\n\", p4) //p4=main.person{name:\"\", city:\"\", age:0}\n\np5 := person{\n\tname: \"小王子\",\n\tcity: \"北京\",\n\tage:  18,\n}\nfmt.Printf(\"p5=%#v\\n\", p5) //p5=main.person{name:\"小王子\", city:\"北京\", age:18}\n\np6 := \u0026person{\n\tname: \"小王子\",\n\tcity: \"北京\",\n\tage:  18,\n}\nfmt.Printf(\"p6=%#v\\n\", p6) //p6=\u0026main.person{name:\"小王子\", city:\"北京\", age:18}\n\np8 := \u0026person{\n\t\"沙河娜扎\",\n\t\"北京\",\n\t28,\n}\nfmt.Printf(\"p8=%#v\\n\", p8) //p8=\u0026main.person{name:\"沙河娜扎\", city:\"北京\", age:28}\n```\n\n- 匿名结构体\n\n```\nvar user struct{Name string; Age int}\nuser.Name = \"xx\"\nuser.Age = 18\nfmt.Printf(\"%#v\\n\", user)\nfmt.Printf(\"user: %T\\n\", \u0026user)//user: *struct { Name string; Age int }\n```\n\n- 结构体函数\n```\nfunc (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {\n    函数体\n}\n```\n\n```\n//Person 结构体\ntype Person struct {\n\tname string\n\tage  int8\n}\n\n//NewPerson 构造函数\nfunc NewPerson(name string, age int8) *Person {\n\treturn \u0026Person{\n\t\tname: name,\n\t\tage:  age,\n\t}\n}\n\n//Dream Person做梦的方法\nfunc (p Person) Dream() {\n\tfmt.Printf(\"%s的梦想是学好Go语言！\\n\", p.name)\n}\n\nfunc main() {\n\tp1 := NewPerson(\"小王子\", 25)\n\tp1.Dream()\n}\n```\n\n- 结构体的“继承”\n\n```\n//Animal 动物\ntype Animal struct {\n\tname string\n}\n\nfunc (a *Animal) move() {\n\tfmt.Printf(\"%s会动！\\n\", a.name)\n}\n\n//Dog 狗\ntype Dog struct {\n\tFeet    int8\n\t*Animal //通过嵌套匿名结构体实现继承\n}\n\nfunc (d *Dog) wang() {\n\tfmt.Printf(\"%s会汪汪汪~\\n\", d.name)\n}\n\nfunc main() {\n\td1 := \u0026Dog{\n\t\tFeet: 4,\n\t\tAnimal: \u0026Animal{ //注意嵌套的是结构体指针\n\t\t\tname: \"乐乐\",\n\t\t},\n\t}\n\td1.wang() //乐乐会汪汪汪~\n\td1.move() //乐乐会动！\n}\n```\n\n- 序列化\n\n```\n//Student 学生\ntype Student struct {\n\tID     int\n\tGender string\n\tName   string\n}\n\n//Class 班级\ntype Class struct {\n\tTitle    string\n\tStudents []*Student\n}\n\nfunc main() {\n\tc := \u0026Class{\n\t\tTitle:    \"101\",\n\t\tStudents: make([]*Student, 0, 200),\n\t}\n\tfor i := 0; i \u003c 10; i++ {\n\t\tstu := \u0026Student{\n\t\t\tName:   fmt.Sprintf(\"stu%02d\", i),\n\t\t\tGender: \"男\",\n\t\t\tID:     i,\n\t\t}\n\t\tc.Students = append(c.Students, stu)\n\t}\n\t//JSON序列化：结构体--\u003eJSON格式的字符串\n\tdata, err := json.Marshal(c)\n\tif err != nil {\n\t\tfmt.Println(\"json marshal failed\")\n\t\treturn\n\t}\n\tfmt.Printf(\"json:%s\\n\", data)\n\t//JSON反序列化：JSON格式的字符串--\u003e结构体\n\tstr := `{\"Title\":\"101\",\"Students\":[{\"ID\":0,\"Gender\":\"男\",\"Name\":\"stu00\"},{\"ID\":1,\"Gender\":\"男\",\"Name\":\"stu01\"},{\"ID\":2,\"Gender\":\"男\",\"Name\":\"stu02\"},{\"ID\":3,\"Gender\":\"男\",\"Name\":\"stu03\"},{\"ID\":4,\"Gender\":\"男\",\"Name\":\"stu04\"},{\"ID\":5,\"Gender\":\"男\",\"Name\":\"stu05\"},{\"ID\":6,\"Gender\":\"男\",\"Name\":\"stu06\"},{\"ID\":7,\"Gender\":\"男\",\"Name\":\"stu07\"},{\"ID\":8,\"Gender\":\"男\",\"Name\":\"stu08\"},{\"ID\":9,\"Gender\":\"男\",\"Name\":\"stu09\"}]}`\n\tc1 := \u0026Class{}\n\terr = json.Unmarshal([]byte(str), c1)\n\tif err != nil {\n\t\tfmt.Println(\"json unmarshal failed!\")\n\t\treturn\n\t}\n\tfmt.Printf(\"%#v\\n\", c1)\n}\n\n```\n\n### package\n\n- 首字母小写，外部包不可见，只能在当前包内使用\n- 首字母大写，外部包可见，可在其他包中使用(变量、函数、结构体、接口)\n- 单行导入\n```\nimport \"包1\"\nimport \"包2\"\n```\n\n- 多行导入\n```\nimport (\n    \"包1\"\n    \"包2\"\n)\n```\n\n- 自定义包名\n\nimport 别名 \"包的路径\"\n\n```\nimport \"fmt\"\nimport m \"github.com/Q1mi/studygo/pkg_test\"\n\nfunc main() {\n\tfmt.Println(m.Add(100, 200))\n\tfmt.Println(m.Mode)\n}\n```\n\n```\nimport (\n    \"fmt\"\n    m \"github.com/Q1mi/studygo/pkg_test\"\n )\n\nfunc main() {\n\tfmt.Println(m.Add(100, 200))\n\tfmt.Println(m.Mode)\n}\n```\n\n- init()函数\n\n![](https://www.liwenzhou.com/images/Go/package/init01.png)\n![](https://www.liwenzhou.com/images/Go/package/init02.png)\n\n\n### 接口\n\n接口在命名时，一般会在单词后面添加er\n\n当方法名首字母是大写且这个接口类型名首字母也是大写时，这个方法可以被接口所在的包（package）之外的代码访问。\n\n```\ntype 接口类型名 interface{\n    方法名1( 参数列表1 ) 返回值列表1\n    方法名2( 参数列表2 ) 返回值列表2\n    …\n}\n```\n\n```\ntype Mover interface {\n\tmove()\n}\n\ntype dog struct {}\n\nfunc (d dog) move() {\n\tfmt.Println(\"狗会动\")\n}\n\nvar x Mover\nvar wangcai = dog{} // 旺财是dog类型\nx = wangcai         // x可以接收dog类型\nvar fugui = \u0026dog{}  // 富贵是*dog类型\nx = fugui           // x可以接收*dog类型\nx.move()\n```\n\n- 空接口\n\n```\n// 定义一个空接口x\nvar x interface{}\ns := \"Hello 沙河\"\nx = s\nfmt.Printf(\"type:%T value:%v\\n\", x, x)\ni := 100\nx = i\nfmt.Printf(\"type:%T value:%v\\n\", x, x)\nb := true\nx = b\nfmt.Printf(\"type:%T value:%v\\n\", x, x)\n\n// 空接口作为函数参数\nfunc showType(a interface{}) {\n\t_, ok := a.(string)\n\tif ok {\n\t\tfmt.Println(\"string\")\n\t}\n\tfmt.Printf(\"type:%T value:%v\\n\", a, a)\n\n\tswitch v := a.(type) {\n\tcase string:\n\t\tfmt.Printf(\"x is a string，value is %v\\n\", v)\n\tcase int:\n\t\tfmt.Printf(\"x is a int is %v\\n\", v)\n\tcase bool:\n\t\tfmt.Printf(\"x is a bool is %v\\n\", v)\n\tdefault:\n\t\tfmt.Println(\"unsupport type！\")\n\t}\n}\n```\n\n### 反射\n\n```\nfunc reflectX(x interface{}) {\n\tt := reflect.TypeOf(x)\n\tfmt.Printf(\"type: %v, kind: %v\\n\", t.Name(), t.Kind())\n\tv := reflect.ValueOf(x)\n\n\tif v.Kind() == reflect.Int64 {\n\t\tv.SetInt(100) //修改的是副本，reflect包会引发panic\n\t}\n\t// 反射中使用 Elem()方法获取指针对应的值\n\tif v.Elem().Kind() == reflect.Int64 {\n\t\tv.Elem().SetInt(200)\n\t}\n}\n```\n\n- isNil()\n\n报告v持有的值是否为nil。v持有的值的分类必须是通道、函数、接口、映射、指针、切片之一；否则IsNil函数会导致panic\n\n- isValid()\n\n返回v是否持有一个值。如果v是Value零值会返回假，此时v除了IsValid、String、Kind之外的方法都会导致panic\n\n- 结构体反射\n\n```\nField(i int) StructField\t根据索引，返回索引对应的结构体字段的信息。\nNumField() int\t返回结构体成员字段数量。\nFieldByName(name string) (StructField, bool)\t根据给定字符串返回字符串对应的结构体字段的信息。\nFieldByIndex(index []int) StructField\t多层成员访问时，根据 []int 提供的每个结构体的字段索引，返回字段的信息。\nFieldByNameFunc(match func(string) bool) (StructField,bool)\t根据传入的匹配函数匹配需要的字段。\nNumMethod() int\t返回该类型的方法集中方法的数目\nMethod(int) Method\t返回该类型方法集中的第i个方法\nMethodByName(string)(Method, bool)\t根据方法名返回该类型方法集中的方法\n```\n\n```\n// 给student添加两个方法 Study和Sleep(注意首字母大写)\nfunc (s student) Study() string {\n\tmsg := \"好好学习，天天向上。\"\n\tfmt.Println(msg)\n\treturn msg\n}\n\nfunc (s student) Sleep() string {\n\tmsg := \"好好睡觉，快快长大。\"\n\tfmt.Println(msg)\n\treturn msg\n}\n\nfunc printMethod(x interface{}) {\n\tt := reflect.TypeOf(x)\n\tv := reflect.ValueOf(x)\n\n\tfmt.Println(t.NumMethod())\n\tfor i := 0; i \u003c v.NumMethod(); i++ {\n\t\tmethodType := v.Method(i).Type()\n\t\tfmt.Printf(\"method name:%s\\n\", t.Method(i).Name)\n\t\tfmt.Printf(\"method:%s\\n\", methodType)\n\t\t// 通过反射调用方法传递的参数必须是 []reflect.Value 类型\n\t\tvar args = []reflect.Value{}\n\t\tv.Method(i).Call(args)\n\t}\n}\n```\n\n### 并发 \n\n```\nvar wg sync.WaitGroup\n\nfunc hello(i int) {\n\tdefer wg.Done() // goroutine结束就登记-1\n\tfmt.Println(\"Hello Goroutine!\", i)\n}\nfunc main() {\n\n\tfor i := 0; i \u003c 10; i++ {\n\t\twg.Add(1) // 启动一个goroutine就登记+1\n\t\tgo hello(i)\n\t}\n\twg.Wait() // 等待所有登记的goroutine都结束\n}\n```\n\n### 网络编程\n\n### 单元测试\n\n```\n类型\t格式\t作用\n测试函数\t函数名前缀为Test\t测试程序的一些逻辑行为是否正确\n基准函数\t函数名前缀为Benchmark\t测试函数的性能\n示例函数\t函数名前缀为Example\t为文档提供示例文档\n```\n\n```\n//Demo_test.go\n\npackage main\n\nimport (\n\t\"testing\"\n)\n\nfunc TestAdd(t *testing.T) {\n\texcepted := 3\n\tgot := 1 + 2\n\tif got != excepted {\n\t\tt.Errorf(\"excepted:%v, got:%v\", excepted, got) // 测试失败输出错误提示\n\t}\n}\n```\n\n### 常用标准库\n\n- math\n\n```\n//开方\nmath.Sqrt\n```\n\n- fmat与格式化占位符\n\n```\n//Print 标准输出\n//Printf 格式化输出\n//Println 输出的内容结尾添加一个换行符\n\n//输出到一个io.Writer接口类型的变量w中，我们通常用这个函数往文件中写入内容\n//Fprint\n//Fprintf\n//Fprintln\n\n//输出到字符串\n//Sprint\n//Sprintf\n//Sprintln\n\n//Errorf 格式化字符串对应的错误\n\n//格式化占位符\n%v\t值的默认格式表示\n%+v\t类似%v，但输出结构体时会添加字段名\n%#v\t值的Go语法表示\n%T\t打印值的类型\n%%\t百分号\n%t 布尔值 true/false\n整型\n%b\t表示为二进制\n%c\t该值对应的unicode码值\n%d\t表示为十进制\n%o\t表示为八进制\n%x\t表示为十六进制，使用a-f\n%X\t表示为十六进制，使用A-F\n%U\t表示为Unicode格式：U+1234，等价于”U+%04X”\n%q\t该值对应的单引号括起来的go语法字符字面值，必要时会采用安全的转义表示\n浮点数与复数\n%b\t无小数部分、二进制指数的科学计数法，如-123456p-78\n%e\t科学计数法，如-1234.456e+78\n%E\t科学计数法，如-1234.456E+78\n%f\t有小数部分但无指数部分，如123.456\n%F\t等价于%f\n%g\t根据实际情况采用%e或%f格式（以获得更简洁、准确的输出）\n%G\t根据实际情况采用%E或%F格式（以获得更简洁、准确的输出）\n字符串和[]byte\n%s\t直接输出字符串或者[]byte\n%q\t该值对应的双引号括起来的go语法字符串字面值，必要时会采用安全的转义表示\n%x\t每个字节用两字符十六进制数表示（使用a-f\n%X\t每个字节用两字符十六进制数表示（使用A-F）\n指针\n%p\t表示为十六进制，并加上前导的0x\n宽度标识符\n%f\t默认宽度，默认精度\n%9f\t宽度9，默认精度\n%.2f\t默认宽度，精度2\n%9.2f\t宽度9，精度2\n%9.f\t宽度9，精度0\n```\n\n```\n\nbufio.NewReader//从终端获取完整内容\n\nreader := bufio.NewReader(os.Stdin) // 从标准输入生成读对象\nfmt.Print(\"请输入内容：\")\ntext, _ := reader.ReadString('\\n') // 读到换行\ntext = strings.TrimSpace(text)\nfmt.Printf(\"%#v\\n\", text)\n```\n\n- time\n\n```\n//获取当前时间\nnow := time.Now()\nfmt.Printf(\"current time: %v\\n\", now)\n\nyear := now.Year()     //年\nmonth := now.Month()   //月\nday := now.Day()       //日\nhour := now.Hour()     //小时\nminute := now.Minute() //分钟\nsecond := now.Second() //秒\nfmt.Printf(\"%d-%02d-%02d %02d:%02d:%02d\\n\", year, month, day, hour, minute, second)\n\n//获取当前时间戳\ntimestamp1 := now.Unix()     //时间戳\ntimestamp2 := now.UnixNano() //纳秒时间戳\nfmt.Printf(\"current timestamp1:%v\\n\", timestamp1)\nfmt.Printf(\"current timestamp2:%v\\n\", timestamp2)\n\n//时间间隔(纳秒为单位)\n// const (\n// \tNanosecond  Duration = 1\n// \tMicrosecond          = 1000 * Nanosecond\n// \tMillisecond          = 1000 * Microsecond\n// \tSecond               = 1000 * Millisecond\n// \tMinute               = 60 * Second\n// \tHour                 = 60 * Minute\n// )\n\n//时间操作\nlater := now.Add(time.Hour) // 当前时间加1小时后的时间\nfmt.Println(later)\n\nd := now.Sub(later)\nfmt.Println(d)\n\nfmt.Printf(\"时间是否相等: %t\\n\", later.Equal(now))\nfmt.Printf(\"时间是否在xx之前: %t\\n\", later.Before(now))\nfmt.Printf(\"时间是否在xx之后: %t\\n\", later.After(now))\n\n//定时器\nticker := time.Tick(time.Second) //定义一个1秒间隔的定时器\nfor i := range ticker {\n\tfmt.Println(i) //每秒都会执行的任务\n\tbreak\n}\n\n//时间格式化(格式化的模板为Go的出生时间2006年1月2号15点04分 Mon Jan)\nfmt.Println(now.Format(\"2006-01-02 15:04:05\"))\n```\n\n- 获取命令行参数\n\n```\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n)\n\n//os.Args demo\nfunc main() {\n\t//os.Args是一个[]string\n\tif len(os.Args) \u003e 0 {\n\t\tfor index, arg := range os.Args {\n\t\t\tfmt.Printf(\"args[%d]=%v\\n\", index, arg)\n\t\t}\n\t}\n}\n```\n\n- 文件操作\n\n```\n//打开关闭文件\nfile, err := os.Open(\"./main.go\")\nif err != nil {\n\tfmt.Println(\"open file failed!, err:\", err)\n\treturn\n}\ndefer file.Close()\n//读取文件\nvar tmp = make([]byte, 128)\nn, err := file.Read(tmp)\nif err == io.EOF {\n\tfmt.Println(\"文件读完了\")\n\treturn\n}\nif err != nil {\n\tfmt.Println(\"read file failed, err:\", err)\n\treturn\n}\nfmt.Printf(\"读取了%d字节数据\\n\", n)\nfmt.Println(string(tmp[:n]))\n\n//循环读取文件所有内容\nvar content []byte\nfor {\n\tn, err := file.Read(tmp)\n\tif err == io.EOF {\n\t\tfmt.Println(\"文件读完了\")\n\t\tbreak\n\t}\n\tif err != nil {\n\t\tfmt.Println(\"read file failed, err:\", err)\n\t\treturn\n\t}\n\tcontent = append(content, tmp[:n]...)\n}\nfmt.Println(string(content))\n\n// bufio按行读取示例\nreader := bufio.NewReader(file)\nfor {\n\tline, err := reader.ReadString('\\n')\n\tif err == io.EOF {\n\t\tif len(line) != 0 {\n\t\t\tfmt.Println(line)\n\t\t}\n\t\tbreak\n\t}\n\tif err != nil {\n\t\tfmt.Println(\"read file failed, err:\", err)\n\t\treturn\n\t}\n\tfmt.Print(line)\n}\n\n//ioutil读取整个文件\nbuf, err := ioutil.ReadFile(\"./main.go\")\nif err != nil {\n\tfmt.Println(\"read file failed, err: \", err)\n\treturn\n}\nfmt.Println(string(buf))\n\n//file2, err := os.OpenFile(\"output.txt\", os.O_CREATE | os.O_TRUNC | os.O_WRONLY, 0666)\n//写入\n// file.Write([]byte(str))       //写入字节切片数据\n// file.WriteString(\"hello 小王子\") //直接写入字符串数据\n\n// writer := bufio.NewWriter(file)\n// writer.WriteString(\"hello沙河\\n\") //将数据先写入缓存\n// writer.Flush() //将缓存中的内容写入文件\n\n//err := ioutil.WriteFile(\"./xx.txt\", []byte(str), 0666)\n```\n\n- strconv包\n\n```\n//string -\u003e int\ns1 := \"100\"\ni1, err := strconv.Atoi(s1)\nif err != nil {\n\tfmt.Println(\"can't convert to int\")\n} else {\n\tfmt.Printf(\"type: %T value: %#v\\n\", i1, i1)\n}\n\n//int -\u003e string\ni2 := 200\ns2 := strconv.Itoa(i2)\nfmt.Printf(\"type:%T value:%#v\\n\", s2, s2)\n\n//parse函数\n//string -\u003e bool\ns3 := \"false\"\nb1, _ := strconv.ParseBool(s3)\nfmt.Printf(\"type:%T value:%#v\\n\", b1, b1)\n\n//string -\u003e int\ns4 := \"100\"\ni3, err := strconv.Atoi(s4)\nif err != nil {\n\tfmt.Println(\"can't convert to int\")\n} else {\n\tfmt.Printf(\"type: %T value: %#v\\n\", i3, i3)\n}\n//ParseUint 类似ParseInt但不接受正负号，用于无符号整型\n\n//string -\u003e float\ns5 := \"3.14\"\nf1, _ := strconv.ParseFloat(s5, 2)\nfmt.Printf(\"type:%T value:%#v\\n\", f1, f1)\n\n//Format系列函数\n//FormatBool\n//FormatInt\nvar i4 int64 = 0xff\nfmt.Printf(\"%#v %#v %#v\\n\", strconv.FormatInt(i4, 2), strconv.FormatInt(i4, 10), strconv.FormatInt(i4, 16))\n//FormatUint\n//FormatFloat\n```\n\n### 问题\n\n```\ntype student struct {\n\tname string\n\tage  int\n}\n\nfunc main() {\n\tm := make(map[string]*student)\n\tstus := []student{\n\t\t{name: \"小王子\", age: 18},\n\t\t{name: \"娜扎\", age: 23},\n\t\t{name: \"大王八\", age: 9000},\n\t}\n\n\tfor _, stu := range stus {\n\t\tm[stu.name] = \u0026stu\n\t}\n\tfor k, v := range m {\n\t\tfmt.Println(k, \"=\u003e\", v.name)\n\t}\n}\n大王八 =\u003e 大王八\n小王子 =\u003e 大王八\n娜扎 =\u003e 大王八\n???\nhttps://segmentfault.com/a/1190000017527311?utm_campaign=studygolang.com\u0026utm_medium=studygolang.com\u0026utm_source=studygolang.com\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftyp0520%2Fgolang-learning","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftyp0520%2Fgolang-learning","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftyp0520%2Fgolang-learning/lists"}