Go语言基础笔记(二)| 青训营笔记

107 阅读12分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记。

2、Golang语言基础

2.1 结构

Go 语言的基础组成有以下几个部分:

  • 包声明
  • 引入包
  • 函数
  • 变量
  • 语句 & 表达式
  • 注释

例如:

1
package main
23
import "fmt"
45
func main() {
6
   /* 这是我的第一个简单的程序 */
7
   fmt.Println("Hello, World!")
8
}
  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 )。

2.2 基础语法

Go 标记

Go 程序可以由多个标记组成,可以是关键字,标识符,常量,字符串,符号。如以下 GO 语句由 6 个标记组成:

1
fmt.Println("Hello, World!")

6 个标记是(每行一个):

1
1. fmt
2
2. .
3
3. Println
4
4. (
5
5. "Hello, World!"
6
6. )

行分隔符

在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。

如果你打算将多个语句写在同一行,它们则必须使用 ; 人为区分,但在实际开发中我们并不鼓励这种做法。

以下为两个语句:

fmt.Println("Hello, World!") fmt.Println("Hello, Golang!")


注释

注释不会被编译,每一个包应该有相关注释。

单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾。如:

1
// 单行注释
2
/*
3
 我是多行注释
4
 */

标识符

标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(AZ和az)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。

以下是有效的标识符:

1
mahesh   kumar   abc   move_name   a_123
2
myname50   _temp   j   a23b9   retVal

以下是无效的标识符:

  • 1ab(以数字开头)
  • case(Go 语言的关键字)
  • a+b(运算符是不允许的)

字符串连接

Go 语言的字符串可以通过 + 实现:

实例

package main import "fmt" func main() { fmt.Println("Golang" + "123") }

以上实例输出结果为:

1
Golang123

关键字

下面列举了 Go 代码中会使用到的 25 个关键字或保留字:

breakdefaultfuncinterfaceselect
casedefergomapstruct
chanelsegotopackageswitch
constfallthroughifrangetype
continueforimportreturnvar

除了以上介绍的这些关键字,Go 语言还有 36 个预定义标识符:

appendboolbytecapclosecomplexcomplex64complex128uint16
copyfalsefloat32float64imagintint8int16uint32
int32int64iotalenmakenewnilpanicuint64
printprintlnrealrecoverstringtrueuintuint8uintptr

程序一般由关键字、常量、变量、运算符、类型和函数组成。

程序中可能会使用到这些分隔符:括号 (),中括号 [] 和大括号 {}。

程序中可能会使用到这些标点符号:.、,、;、: 和 …。

2.3 数据类型

image-20220506163626749

stringsAPI

1
package main
23
import (
4
    "fmt"
5
    "strings"
6
)
78
func main() {
9
    a := "hello"
10
    fmt.Println(strings.Contains(a, "ll"))                // true
11
    fmt.Println(strings.Count(a, "l"))                    // 2
12
    fmt.Println(strings.HasPrefix(a, "he"))               // true
13
    fmt.Println(strings.HasSuffix(a, "llo"))              // true
14
    fmt.Println(strings.Index(a, "ll"))                   // 2
15
    fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
16
    fmt.Println(strings.Repeat(a, 2))                     // hellohello
17
    fmt.Println(strings.Replace(a, "e", "E", -1))         // hEllo
18
    fmt.Println(strings.Split("a-b-c", "-"))              // [a b c]
19
    fmt.Println(strings.ToLower(a))                       // hello
20
    fmt.Println(strings.ToUpper(a))                       // HELLO
21
    fmt.Println(len(a))                                   // 5
22
    b := "你好"
23
    fmt.Println(len(b)) // 6
24
}
25

fmtAPI

1
package main
23
import "fmt"
45
type point struct {
6
    x, y int
7
}
89
func main() {
10
    s := "hello"
11
    n := 123
12
    p := point{1, 2}
13
    fmt.Println(s, n) // hello 123
14
    fmt.Println(p)    // {1 2}
1516
    fmt.Printf("s=%v\n", s)  // s=hello
17
    fmt.Printf("n=%v\n", n)  // n=123
18
    fmt.Printf("p=%v\n", p)  // p={1 2}
19
    fmt.Printf("p=%+v\n", p) // p={x:1 y:2}
20
    fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2}
2122
    f := 3.141592653
23
    fmt.Println(f)          // 3.141592653
24
    fmt.Printf("%.2f\n", f) // 3.14
25
}
26

jsonAPI

1
package main
23
import (
4
    "encoding/json"
5
    "fmt"
6
)
78
type userInfo struct {
9
    Name  string
10
    Age   int `json:"age"`  //这一步作用:输出json格式的时候  输出age
11
    Hobby []string
12
}
1314
func main() {
15
    a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
16
    buf, err := json.Marshal(a)
17
    if err != nil {
18
        panic(err)
19
    }
20
    fmt.Println(buf)         // [123 34 78 97...]
21
    fmt.Println(string(buf)) // {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]}
2223
    buf, err = json.MarshalIndent(a, "", "\t")
24
    if err != nil {
25
        panic(err)
26
    }
27
    fmt.Println(string(buf))
2829
    var b userInfo
30
    err = json.Unmarshal(buf, &b)
31
    if err != nil {
32
        panic(err)
33
    }
34
    fmt.Printf("%#v\n", b) // main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
35
}
36

timeAPI

1
package main
23
import (
4
    "fmt"
5
    "time"
6
)
78
func main() {
9
    now := time.Now()
10
    fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933
11
    t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
12
    t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
13
    fmt.Println(t)                                                  // 2022-03-27 01:25:36 +0000 UTC
14
    fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25
15
    fmt.Println(t.Format("2006-01-02 15:04:05"))                    // 2022-03-27 01:25:36
16
    diff := t2.Sub(t)
17
    fmt.Println(diff)                           // 1h5m0s
18
    fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900
19
    t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
20
    if err != nil {
21
        panic(err)
22
    }
23
    fmt.Println(t3 == t)    // true
24
    fmt.Println(now.Unix()) // 1648738080
25
}
26

strconvAPI数字解析

1
package main
23
import (
4
    "fmt"
5
    "strconv"
6
)
78
func main() {
9
    f, _ := strconv.ParseFloat("1.234", 64)
10
    fmt.Println(f) // 1.234
1112
    n, _ := strconv.ParseInt("111", 10, 64)
13
    fmt.Println(n) // 111
1415
    n, _ = strconv.ParseInt("0x1000", 0, 64)
16
    fmt.Println(n) // 4096
1718
    n2, _ := strconv.Atoi("123")
19
    fmt.Println(n2) // 123
2021
    n2, err := strconv.Atoi("AAA")
22
    fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
23
}
24

osAPI进程信息API

1
package main
23
import (
4
    "fmt"
5
    "os"
6
    "os/exec"
7
)
89
func main() {
10
    // go run example/20-env/main.go a b c d
11
    fmt.Println(os.Args)           // [/var/folders/8p/n34xxfnx38dg8bv_x8l62t_m0000gn/T/go-build3406981276/b001/exe/main a b c d]
12
    fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin...
13
    fmt.Println(os.Setenv("AA", "BB"))
1415
    buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
16
    if err != nil {
17
        panic(err)
18
    }
19
    fmt.Println(string(buf)) // 127.0.0.1       localhost
20
}
21

2.4 语言变量

Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。

声明变量的一般形式是使用 var 关键字:

1
//单变量声明
2
var identifier type
3
//多变量声明
4
var identifier1, identifier2 type

若未初始化则使用默认值

1
数值类型(包括complex64/128)为 0
23
布尔类型为 false
45
字符串为 ""(空字符串)
67
以下几种类型为 nil8
var a *int
9
var a []int
10
var a map[string] int
11
var a chan int
12
var a func(string) int
13
var a error // error 是接口

例如:

1
package main
23
import "fmt"
45
//全局变量
6
var n7 = 9.9
78
//全局变量简写形式
9
var (
10
    n8 = "jack"
11
    n9 = 123
12
)
1314
func main() {
15
    // //1.指定变量数据类型
16
    // var age int
17
    // age = 19
18
    // fmt.Println(age)
1920
    // //2.指定变量数据类型
21
    // var num int = 20
22
    // fmt.Println(num)
2324
    // //3.未指定变量数据类型,根据=后面值自动补充数据类型
25
    // var name = "yg"
26
    // fmt.Println(name)
2728
    // //4.简短形式,使用 := 赋值操作符(即省略var关键字)
29
    // sex := "男"
30
    // fmt.Println(sex)
31
    
32
    var i int
33
    var f float64
34
    var b bool
35
    var s string
36
    fmt.Printf("%v %v %v %q\n", i, f, b, s)
3738
    var n1,n2,n3 = 10,"123",1.2
39
    fmt.Println(n1)
40
    fmt.Println(n2)
41
    fmt.Println(n3)
4243
    var n4,n5,n6 int
44
    fmt.Println(n4)
45
    fmt.Println(n5)
46
    fmt.Println(n6)
4748
    fmt.Println(n7)
49
    fmt.Println(n8)
50
    fmt.Println(n9)
5152
}

2.5 语言常量

常量是一个简单值的标识符,在程序运行时,不会被修改的量。

常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。

常量的定义格式:

1
const identifier [type] = value

你可以省略类型说明符 [type],因为编译器可以根据变量的值来推断其类型。

  • 显式类型定义: const b string = "abc"
  • 隐式类型定义: const b = "abc"

多个相同类型的声明可以简写为:

1
const c_name1, c_name2 = value1, value2

常量还可以用作枚举:

1
const (
2
    Unknown = 0
3
    Female = 1
4
    Male = 2
5
)

2.6 运算符

运算符用于在程序运行时执行数学或逻辑运算。

Go 语言内置的运算符有:

  • 算术运算符

  • 关系运算符

  • 逻辑运算符

  • 位运算符

  • 赋值运算符

  • 其他运算符

    • &返回变量存储地址&a; 将给出变量的实际地址。
      *指针变量。*a; 是一个指针变量

基本和其他语言类似

但是只有a++没有 ++a

2.7 条件语句

if-else if

1
package main
23
import "fmt"
45
func main() {
67
    sex := "男"
8
    if sex=="男"{
9
        fmt.Println(sex)
10
    }
1112
    /* 定义局部变量 */
13
    var a int = 10
14
 
15
    /* 使用 if 语句判断布尔表达式 */
16
    if a < 20 {
17
        /* 如果条件为 true 则执行以下语句 */
18
        fmt.Printf("a 小于 20\n" )
19
    }
20
    fmt.Printf("a 的值为 : %d\n", a)
2122
    if 7%2 == 0 {
23
        fmt.Println("7 is even")
24
    } else {
25
        fmt.Println("7 is odd")
26
    }
2728
    if 8%4 == 0 {
29
        fmt.Println("8 is divisible by 4")
30
    }
3132
    if num := 9; num < 0 {
33
        fmt.Println(num, "is negative")
34
    } else if num < 10 {
35
        fmt.Println(num, "has 1 digit")
36
    } else {
37
        fmt.Println(num, "has multiple digits")
38
    }
39
}
40

switch

switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。

switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break。

switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用 fallthrough

1
package main
23
import "fmt"
45
func main(){
6
    /* 定义局部变量 */
7
   var grade string = "B"
8
   var marks int = 90
910
   switch marks {
11
      case 90: grade = "A"
12
      case 80: grade = "B"
13
      case 50,60,70 : grade = "C"
14
      default: grade = "D"  
15
   }
1617
   switch {
18
      case grade == "A" :
19
         fmt.Printf("优秀!\n" )    
20
      case grade == "B", grade == "C" :
21
         fmt.Printf("良好\n" )      
22
      case grade == "D" :
23
         fmt.Printf("及格\n" )      
24
      case grade == "F":
25
         fmt.Printf("不及格\n" )
26
      default:
27
         fmt.Printf("差\n" );
28
   }
29
   fmt.Printf("你的等级是 %s\n", grade ); 
30
}

2.8 循环语句

语法

Go 语言的 For 循环有 3 种形式,只有其中的一种使用分号。

和 C 语言的 for 一样:

1
for init; condition; post { }

和 C 的 while 一样:

1
for condition { }

和 C 的 for(;;) 一样:

1
for { }
  • init: 一般为赋值表达式,给控制变量赋初值;
  • condition: 关系表达式或逻辑表达式,循环控制条件;
  • post: 一般为赋值表达式,给控制变量增量或减量。

for语句执行过程如下:

  • 1、先对表达式 1 赋初值;
  • 2、判别赋值表达式 init 是否满足给定条件,若其值为真,满足循环条件,则执行循环体内语句,然后执行 post,进入第二次循环,再判别 condition;否则判断 condition 的值为假,不满足条件,就终止for循环,执行循环体外语句。
1
package main
23
import "fmt"
45
func main() {
6
    i := 1
7
    for {
8
        fmt.Println("loop")
9
        break
10
    }
11
    for j := 7; j < 9; j++ {
12
        fmt.Println(j)
13
    }
1415
    for n := 0; n < 5; n++ {
16
        if n%2 == 0 {
17
            continue
18
        }
19
        fmt.Println(n)
20
    }
21
    for i <= 3 {
22
        fmt.Println(i)
23
        i++
24
    }
25
}
26

2.9 函数

函数是基本的代码块,用于执行一个任务。

Go 语言最少有个 main() 函数。

你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。

函数声明告诉了编译器函数的名称,返回类型,和参数。

Go 语言标准库提供了多种可动用的内置的函数。例如,len() 函数可以接受不同类型参数并返回该类型的长度。如果我们传入的是字符串则返回字符串的长度,如果传入的是数组,则返回数组中包含的元素个数。

函数定义

Go 语言函数定义格式如下:

1
func function_name( [parameter list] ) [return_types] {
2
   函数体
3
}

函数定义解析:

  • func:函数由 func 开始声明
  • function_name:函数名称,参数列表和返回值类型构成了函数签名。
  • parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
  • return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
  • 函数体:函数定义的代码集合。

例如 返回双数中的较大值

1
package main
23
import "fmt"
45
func main(){
6
   
7
    fmt.Println(nums_max(1,2))
8
}
9
func nums_max(num1,num2 int) int{
1011
    if num1>num2{
12
        return num1
13
    }else{
14
        return num2
15
    }
16
}

函数返回多个值

1
package main
23
import "fmt"
45
func swap(x, y string) (string, string) {
6
    return y, x
7
}
89
func main() {
10
    a, b := swap("go", "java")
11
    fmt.Println(a, b)
12
}

函数参数

函数如果使用参数,该变量可称为函数的形参。

形参就像定义在函数体内的局部变量。

调用函数,可以通过两种方式来传递参数:

传递类型描述
值传递值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数

2.10 变量作用域

作用域为已声明标识符所表示的常量、类型、变量、函数或包在源代码中的作用范围。

Go 语言中变量可以在三个地方声明:

  • 函数内定义的变量称为局部变量
  • 函数外定义的变量称为全局变量
  • 函数定义中的变量称为形式参数

2.11 数组

声明数组

Go 语言数组声明需要指定元素类型及元素个数,语法格式如下:

1
var variable_name [SIZE] variable_type

以上为一维数组的定义方式。例如以下定义了数组 balance 长度为 10 类型为 float32:

1
var balance [10] float32

初始化数组

以下演示了数组初始化:

1
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

我们也可以通过字面量在声明数组的同时快速初始化数组:

1
balance := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

如果数组长度不确定,可以使用 ... 代替数组的长度,编译器会根据元素个数自行推断数组的长度:

1
var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
23
balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

如果设置了数组的长度,我们还可以通过指定下标来初始化元素:

1
//  将索引为 1 和 3 的元素初始化
2
balance := [5]float32{1:2.0,3:7.0}

初始化数组中 {} 中的元素个数不能大于 [] 中的数字。

如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小:

1
 balance[4] = 50.0

总结:

1
package main
23
import "fmt"
45
func main() {
67
    var arr[5]string
8
    for i:=0;i<5;i++{
9
        arr[i] = "str"
10
    }
11
    fmt.Println(arr)
121314
    var a [5]int
15
    a[4] = 100
16
    fmt.Println("get:", a[2])
17
    fmt.Println("len:", len(a))
1819
    b := [5]int{1, 2, 3, 4, 5}
20
    fmt.Println(b)
2122
    var twoD [2][3]int
23
    for i := 0; i < 2; i++ {
24
        for j := 0; j < 3; j++ {
25
            twoD[i][j] = i + j
26
        }
27
    }
28
    fmt.Println("2d: ", twoD)
29
}
30

2.12 切片(Slice)

Go 语言切片是对数组的抽象。

Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。

定义切片

你可以声明一个未指定大小的数组来定义切片:

1
var identifier []type

切片不需要说明长度。

或使用 make() 函数来创建切片:

1
var slice1 []type = make([]type, len)
23
也可以简写为
45
slice1 := make([]type, len)

也可以指定容量,其中 capacity 为可选参数。

1
make([]T, length, capacity)

这里 len 是数组的长度并且也是切片的初始长度。

切片初始化

1
s :=[] int {1,2,3 } 

直接初始化切片, [] 表示是切片类型, {1,2,3} 初始化值依次是 1,2,3,其 cap=len=3

1
s := arr[:] 

初始化切片 s,是数组 arr 的引用。

1
s := arr[startIndex:endIndex] 

将 arr 中从下标 startIndex 到 endIndex-1 下的元素创建为一个新的切片。

1
s := arr[startIndex:] 

默认 endIndex 时将表示一直到arr的最后一个元素。

1
s := arr[:endIndex] 

默认 startIndex 时将表示从 arr 的第一个元素开始。

1
s1 := s[startIndex:endIndex] 

通过切片 s 初始化切片 s1。

1
s :=make([]int,len,cap) 

通过内置函数 make() 初始化切片s[]int 标识为其元素类型为 int 的切片。

len() 和 cap() 函数

切片是可索引的,并且可以由 len() 方法获取长度。

切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。

空(nil)切片

一个切片在未初始化之前默认为 nil,长度为 0

切片截取

可以通过设置下限及上限来设置截取切片 [lower-bound:upper-bound]

append() 和 copy() 函数

如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来。

下面的代码描述了从拷贝切片的 copy 方法和向切片追加新元素的 append 方法。

总代码:

1
package main
23
import "fmt"
45
func main() {
67
    s := make([]string, 3)
8
    s[0] = "a"
9
    s[1] = "b"
10
    s[2] = "c"
11
    fmt.Println("get:", s[2])   // c
12
    fmt.Println("len:", len(s)) // 3
1314
    s = append(s, "d")
15
    s = append(s, "e", "f")
16
    fmt.Println(s) // [a b c d e f]
1718
    fmt.Println("len:", len(s))//6
1920
    c := make([]string, len(s))
21
    copy(c, s)
22
    fmt.Println(c) // [a b c d e f]
2324
    fmt.Println(s[2:5]) // [c d e]
25
    fmt.Println(s[:5])  // [a b c d e]
26
    fmt.Println(s[2:])  // [c d e f]
2728
    good := []string{"g", "o", "o", "d"}
29
    fmt.Println(good) // [g o o d]
30
}
31

2.13 Map集合

Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。

Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。

定义 Map

可以使用内建函数 make 也可以使用 map 关键字来定义 Map:

1
/* 声明变量,默认 map 是 nil */
2
var map_variable map[key_data_type]value_data_type
34
/* 使用 make 函数 */
5
map_variable := make(map[key_data_type]value_data_type)

如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对

delete() 函数

delete() 函数用于删除集合的元素, 参数为 map 和其对应的 key

总代码

1
package main
23
import "fmt"
45
func main() {
6
    m := make(map[string]int)
7
    m["one"] = 1
8
    m["two"] = 2
9
    fmt.Println(m)           // map[one:1 two:2]
10
    fmt.Println(len(m))      // 2
11
    fmt.Println(m["one"])    // 1a
12
    fmt.Println(m["unknow"]) // 0
1314
    r, ok1 := m["unknow"]
15
    fmt.Println(r, ok1) // 0 false
1617
    delete(m, "one")
1819
    m2 := map[string]int{"one": 1, "two": 2}
20
    var m3 = map[string]int{"one": 1, "two": 2}
21
    fmt.Println(m2, m3)
22
}
23

2.14 范围Range

Go 语言中 range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对。

for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:

1
for key, value := range oldMap {
2
    newMap[key] = value
3
}

以上代码中的 key 和 value 是可以省略。

如果只想读取 key,格式如下:

1
for key := range oldMap

或者这样:

for key, _ := range oldMap

如果只想读取 value,格式如下:

1
for _, value := range oldMap

总代码

1
package main
23
import "fmt"
45
func main() {
6
    nums := []int{2, 3, 4}
7
    sum := 0
8
    for i, num := range nums {
9
        sum += num
10
        if num == 2 {
11
            fmt.Println("index:", i, "num:", num) // index: 0 num: 2
12
        }
13
    }
14
    fmt.Println(sum) // 9
1516
    m := map[string]string{"a": "A", "b": "B"}
17
    for k, v := range m {
18
        fmt.Println(k, v) // b 8; a A
19
    }
20
    for k := range m {
21
        fmt.Println("key", k) // key a; key b
22
    }
23
}
24

2.15 指针

Go 语言中指针是很容易学习的,Go 语言中使用指针可以更简单的执行一些任务。

接下来让我们来一步步学习 Go 语言指针。

我们都知道,变量是一种使用方便的占位符,用于引用计算机内存地址。

Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。

1
package main
23
import "fmt"
45
func add2(n int) {
6
    n += 2
7
}
89
func add2ptr(n *int) {
10
    *n += 2
11
}
1213
func main() {
14
    n := 5
15
    add2(n)
16
    fmt.Println(n) // 5
17
    add2ptr(&n)
18
    fmt.Println(n) // 7
19
}
20

2.16 结构体

Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。

结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。

定义结构体

结构体定义需要使用 type 和 struct 语句。struct 语句定义一个新的数据类型,结构体中有一个或多个成员。type 语句设定了结构体的名称。结构体的格式如下:

1
type struct_variable_type struct {
2
   member definition
3
   member definition
4
   ...
5
   member definition
6
}

一旦定义了结构体类型,它就能用于变量的声明,语法格式如下:

1
variable_name := structure_variable_type {value1, value2...valuen}
23
variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}

总代码

1
package main
23
import "fmt"
45
type user struct {
6
    name     string
7
    password string
8
}
910
func main() {
11
    a := user{name: "wang", password: "1024"}
12
    b := user{"wang", "1024"}
13
    c := user{name: "wang"}
14
    c.password = "1024"
15
    var d user
16
    d.name = "wang"
17
    d.password = "1024"
1819
    fmt.Println(a, b, c, d)                 // {wang 1024} {wang 1024} {wang 1024} {wang 1024}
20
    fmt.Println(checkPassword(a, "1024"))   // true
21
    fmt.Println(checkPassword2(&a, "haha")) // false
22
}
2324
func checkPassword(u user, password string) bool {
25
    return u.password == password
26
}
2728
func checkPassword2(u *user, password string) bool {
29
    return u.password == password
30
}
31

结构体方法

1
package main
23
import "fmt"
45
type user struct {
6
    name     string
7
    password string
8
}
910
func (u user) checkPassword(password string) bool {
11
    return u.password == password
12
}
1314
func (u *user) resetPassword(password string) {
15
    u.password = password
16
}
1718
func main() {
19
    a := user{name: "wang", password: "1024"}
20
    a.resetPassword("2048")
21
    fmt.Println(a.checkPassword("2048")) // true
22
}
23

2.17 错误处理

Go 语言通过内置的错误接口提供了非常简单的错误处理机制。

error类型是一个接口类型,这是它的定义:

1
type error interface {
2
    Error() string
3
}

我们可以在编码中通过实现 error 接口类型来生成错误信息。

函数通常在最后的返回值中返回错误信息。使用errors.New 可返回一个错误信息:

1
package main
23
import (
4
    "errors"
5
    "fmt"
6
)
78
type user struct {
9
    name     string
10
    password string
11
}
1213
func findUser(users []user, name string) (v *user, err error) {
14
    for _, u := range users {
15
        if u.name == name {
16
            return &u, nil
17
        }
18
    }
19
    return nil, errors.New("not found")
20
}
2122
func main() {
23
    u, err := findUser([]user{{"wang", "1024"}}, "wang")
24
    if err != nil {
25
        fmt.Println(err)
26
        return
27
    }
28
    fmt.Println(u.name) // wang
2930
    if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
31
        fmt.Println(err) // not found
32
        return
33
    } else {
34
        fmt.Println(u.name)
35
    }
36
}
37

100以内猜数游戏

 package main
 ​
 import (
     "fmt"
     "math/rand"
     "time"
 )
 ​
 func main() {
     maxNum := 100
     rand.Seed(time.Now().UnixNano())//种子
     secretNumber := rand.Intn(maxNum)
 ​
 ​
     var guessNum int
     for {
         fmt.Println("Please input your guess")
         _,err := fmt.Scanf("%d\n", &guessNum)
         if err!=nil {
             fmt.Println("ERROR!")
             continue
         }
         if(guessNum < secretNumber){
             fmt.Println("Your guess is smaller than the secret number. Please try again")
             fmt.Println("--------------------------------------------------------------")
         }else if(guessNum > secretNumber){
             fmt.Println("Your guess is bigger than the secret number. Please try again")
             fmt.Println("--------------------------------------------------------------")
         }else{
             fmt.Println("You guess is", guessNum)
             fmt.Println("Correct! you Win!")
             break
         }
     }
 }