这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记。
2、Golang语言基础
2.1 结构
Go 语言的基础组成有以下几个部分:
- 包声明
- 引入包
- 函数
- 变量
- 语句 & 表达式
- 注释
例如:
1
package main
2
3
import "fmt"
4
5
func main() {
6
/* 这是我的第一个简单的程序 */
7
fmt.Println("Hello, World!")
8
}
- 第一行代码 package main 定义了包名。你必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
- 下一行 import "fmt" 告诉 Go 编译器这个程序需要使用 fmt 包(的函数,或其他元素),fmt 包实现了格式化 IO(输入/输出)的函数。
- 下一行 func main() 是程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。
- 下一行 / ... / 是注释,在程序执行时将被忽略。单行注释是最常见的注释形式,你可以在任何地方使用以 // 开头的单行注释。多行注释也叫块注释,均已以 /* 开头,并以 */ 结尾,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段。
- 下一行 fmt.Println(...) 可以将字符串输出到控制台,并在最后自动增加换行字符 \n。 使用 fmt.Print("hello, world\n") 可以得到相同的结果。 Print 和 Println 这两个函数也支持使用变量,如:fmt.Println(arr)。如果没有特别指定,它们会以默认的打印格式将变量 arr 输出到控制台。
- 当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如: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 个关键字或保留字:
| break | default | func | interface | select |
|---|---|---|---|---|
| case | defer | go | map | struct |
| chan | else | goto | package | switch |
| const | fallthrough | if | range | type |
| continue | for | import | return | var |
除了以上介绍的这些关键字,Go 语言还有 36 个预定义标识符:
| append | bool | byte | cap | close | complex | complex64 | complex128 | uint16 |
|---|---|---|---|---|---|---|---|---|
| copy | false | float32 | float64 | imag | int | int8 | int16 | uint32 |
| int32 | int64 | iota | len | make | new | nil | panic | uint64 |
| println | real | recover | string | true | uint | uint8 | uintptr |
程序一般由关键字、常量、变量、运算符、类型和函数组成。
程序中可能会使用到这些分隔符:括号 (),中括号 [] 和大括号 {}。
程序中可能会使用到这些标点符号:.、,、;、: 和 …。
2.3 数据类型
stringsAPI
1
package main
2
3
import (
4
"fmt"
5
"strings"
6
)
7
8
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
2
3
import "fmt"
4
5
type point struct {
6
x, y int
7
}
8
9
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}
15
16
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}
21
22
f := 3.141592653
23
fmt.Println(f) // 3.141592653
24
fmt.Printf("%.2f\n", f) // 3.14
25
}
26
jsonAPI
1
package main
2
3
import (
4
"encoding/json"
5
"fmt"
6
)
7
8
type userInfo struct {
9
Name string
10
Age int `json:"age"` //这一步作用:输出json格式的时候 输出age
11
Hobby []string
12
}
13
14
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"]}
22
23
buf, err = json.MarshalIndent(a, "", "\t")
24
if err != nil {
25
panic(err)
26
}
27
fmt.Println(string(buf))
28
29
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
2
3
import (
4
"fmt"
5
"time"
6
)
7
8
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
2
3
import (
4
"fmt"
5
"strconv"
6
)
7
8
func main() {
9
f, _ := strconv.ParseFloat("1.234", 64)
10
fmt.Println(f) // 1.234
11
12
n, _ := strconv.ParseInt("111", 10, 64)
13
fmt.Println(n) // 111
14
15
n, _ = strconv.ParseInt("0x1000", 0, 64)
16
fmt.Println(n) // 4096
17
18
n2, _ := strconv.Atoi("123")
19
fmt.Println(n2) // 123
20
21
n2, err := strconv.Atoi("AAA")
22
fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax
23
}
24
osAPI进程信息API
1
package main
2
3
import (
4
"fmt"
5
"os"
6
"os/exec"
7
)
8
9
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"))
14
15
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
2
3
布尔类型为 false
4
5
字符串为 ""(空字符串)
6
7
以下几种类型为 nil:
8
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
2
3
import "fmt"
4
5
//全局变量
6
var n7 = 9.9
7
8
//全局变量简写形式
9
var (
10
n8 = "jack"
11
n9 = 123
12
)
13
14
func main() {
15
// //1.指定变量数据类型
16
// var age int
17
// age = 19
18
// fmt.Println(age)
19
20
// //2.指定变量数据类型
21
// var num int = 20
22
// fmt.Println(num)
23
24
// //3.未指定变量数据类型,根据=后面值自动补充数据类型
25
// var name = "yg"
26
// fmt.Println(name)
27
28
// //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)
37
38
var n1,n2,n3 = 10,"123",1.2
39
fmt.Println(n1)
40
fmt.Println(n2)
41
fmt.Println(n3)
42
43
var n4,n5,n6 int
44
fmt.Println(n4)
45
fmt.Println(n5)
46
fmt.Println(n6)
47
48
fmt.Println(n7)
49
fmt.Println(n8)
50
fmt.Println(n9)
51
52
}
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
2
3
import "fmt"
4
5
func main() {
6
7
sex := "男"
8
if sex=="男"{
9
fmt.Println(sex)
10
}
11
12
/* 定义局部变量 */
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)
21
22
if 7%2 == 0 {
23
fmt.Println("7 is even")
24
} else {
25
fmt.Println("7 is odd")
26
}
27
28
if 8%4 == 0 {
29
fmt.Println("8 is divisible by 4")
30
}
31
32
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
2
3
import "fmt"
4
5
func main(){
6
/* 定义局部变量 */
7
var grade string = "B"
8
var marks int = 90
9
10
switch marks {
11
case 90: grade = "A"
12
case 80: grade = "B"
13
case 50,60,70 : grade = "C"
14
default: grade = "D"
15
}
16
17
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
2
3
import "fmt"
4
5
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
}
14
15
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
2
3
import "fmt"
4
5
func main(){
6
7
fmt.Println(nums_max(1,2))
8
}
9
func nums_max(num1,num2 int) int{
10
11
if num1>num2{
12
return num1
13
}else{
14
return num2
15
}
16
}
函数返回多个值
1
package main
2
3
import "fmt"
4
5
func swap(x, y string) (string, string) {
6
return y, x
7
}
8
9
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}
2
或
3
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
2
3
import "fmt"
4
5
func main() {
6
7
var arr[5]string
8
for i:=0;i<5;i++{
9
arr[i] = "str"
10
}
11
fmt.Println(arr)
12
13
14
var a [5]int
15
a[4] = 100
16
fmt.Println("get:", a[2])
17
fmt.Println("len:", len(a))
18
19
b := [5]int{1, 2, 3, 4, 5}
20
fmt.Println(b)
21
22
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)
2
3
也可以简写为
4
5
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
2
3
import "fmt"
4
5
func main() {
6
7
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
13
14
s = append(s, "d")
15
s = append(s, "e", "f")
16
fmt.Println(s) // [a b c d e f]
17
18
fmt.Println("len:", len(s))//6
19
20
c := make([]string, len(s))
21
copy(c, s)
22
fmt.Println(c) // [a b c d e f]
23
24
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]
27
28
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
3
4
/* 使用 make 函数 */
5
map_variable := make(map[key_data_type]value_data_type)
如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对
delete() 函数
delete() 函数用于删除集合的元素, 参数为 map 和其对应的 key
总代码
1
package main
2
3
import "fmt"
4
5
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
13
14
r, ok1 := m["unknow"]
15
fmt.Println(r, ok1) // 0 false
16
17
delete(m, "one")
18
19
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
2
3
import "fmt"
4
5
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
15
16
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
2
3
import "fmt"
4
5
func add2(n int) {
6
n += 2
7
}
8
9
func add2ptr(n *int) {
10
*n += 2
11
}
12
13
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}
2
或
3
variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}
总代码
1
package main
2
3
import "fmt"
4
5
type user struct {
6
name string
7
password string
8
}
9
10
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"
18
19
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
}
23
24
func checkPassword(u user, password string) bool {
25
return u.password == password
26
}
27
28
func checkPassword2(u *user, password string) bool {
29
return u.password == password
30
}
31
结构体方法
1
package main
2
3
import "fmt"
4
5
type user struct {
6
name string
7
password string
8
}
9
10
func (u user) checkPassword(password string) bool {
11
return u.password == password
12
}
13
14
func (u *user) resetPassword(password string) {
15
u.password = password
16
}
17
18
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
2
3
import (
4
"errors"
5
"fmt"
6
)
7
8
type user struct {
9
name string
10
password string
11
}
12
13
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
}
21
22
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
29
30
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
}
}
}