一、文件名 & 关键字 & 标识符
-
1.所有go源码以.go结尾
-
2.标识符以字母或下划线开头,大小写敏感
-
3._是特殊标识符,用来忽略结果
-
4.保留关键字
二、Go程序的基本结构
1
2
3
4
5
6
7
8 1package main
2
3import "fmt"
4
5func main() {
6 fmt.Println("hello world")
7}
8
- 任何一个代码文件隶属于一个包
2.import 关键字,引用其他包
1
2
3
4
5
6
7
8 1import ("fmt")
2import ("os")
3通常习惯写成
4import (
5"fmt"
6"os"
7)
8
3.golang可执行程序,package main, 并且有且只有一个main入口函数
4.包中函数调用
a.同一个包中函数,直接调用
b.不同包中函数,通过包名+点+函数名进行调用
5.包访问控制权限
a.大写意味着这个函数/变量是可导出的
b.小写意味着这个函数/变量是私有的,包外部不能访问
小练习
- 写一个程序,对给定一个数字n,求出所有两两相加等于n的组合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 1package main
2
3import "fmt"
4
5func list(n int) {
6 for i := 0; i <= n; i++ {
7 fmt.Printf("%d+%d=%d\n", i, n-i, n)
8 }
9}
10
11func main() {
12 list(10)
13}
14
15// go build -o bin/list.exe go_dev/day2/example1/main
16
练习1
- 一个程序包含两个包add和main,其中add包中有两个变量:Name和age。请问main包中如何访问Name和age?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 1package add
2
3// 方式一
4// var Name string = "hello world"
5// var Age int = 10
6
7// 方式一
8// var Name string = "hello world"
9// var Age int = 10
10
11// 方式二
12var Name string
13var Age int
14
15func Test() {
16 Name = "hello wrold"
17 Age = 20
18}
19
add.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 1package main
2
3import (
4 "fmt"
5 "go_dev/day2/example2/add"
6)
7
8func main() {
9 // 方式一 直接调用
10 // fmt.Println("Name=", add.Name)
11 // fmt.Println("Age=", add.Age)
12
13 // 方式二 先调用函数
14 add.Test()
15 fmt.Println("Name=", add.Name)
16 fmt.Println("Age=", add.Age)
17}
18
main.go
- 包别名的应用,开发一个程序,使用包别名来访问包中的函数?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 1package main
2
3import (
4 "fmt"
5 a "go_dev/day2/example2/add"
6)
7
8func main() {
9 // 方式一 直接调用
10 // fmt.Println("Name=", add.Name)
11 // fmt.Println("Age=", add.Age)
12
13 // 方式二 先调用函数
14 // add.Test()
15 // fmt.Println("Name=", add.Name)
16 // fmt.Println("Age=", add.Age)
17
18 // 包的别名
19 a.Test()
20 fmt.Println("Name=", a.Name)
21 fmt.Println("Age=", a.Age)
22}
23
main.go
- 每个源文件都可以包含一个init函数,这个init函数自动被go运行框架调用。开发一个程序演示这个功能?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 1package add
2
3// 先执行全局变量,在执行init函数, 在执行main函数
4
5// 方式一
6// var Name string = "hello world"
7// var Age int = 10
8
9// 方式二
10var Name string
11var Age int
12
13func Test() {
14 Name = "hello wrold"
15 Age = 20
16}
17
18func init() {
19 Name = "hello wrold"
20 Age = 20
21}
22
add.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 1package main
2
3import (
4 "fmt"
5 // "go_dev/day2/example2/add"
6 a "go_dev/day2/example2/add"
7)
8
9func main() {
10 // 方式一 直接调用
11 // fmt.Println("Name=", add.Name)
12 // fmt.Println("Age=", add.Age)
13
14 // 方式二 先调用函数
15 // add.Test()
16 // fmt.Println("Name=", add.Name)
17 // fmt.Println("Age=", add.Age)
18
19 // 包的别名
20 // a.Test()
21 // fmt.Println("Name=", a.Name)
22 // fmt.Println("Age=", a.Age)
23
24 // init
25 fmt.Println("Name=", a.Name)
26 fmt.Println("Age=", a.Age)
27}
28
main.go
- 包的只初始化,不引用。请开发一个程序,演示这个做法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 1package test
2
3import "fmt"
4
5var Name string = "hello world"
6var Age int = 1000
7
8func init() {
9 fmt.Println("Name=", Name)
10 fmt.Println("Age=", Age)
11
12 Age = 10
13 fmt.Println("Age=", Age)
14 fmt.Println("this is a test....")
15}
16
test.go
1
2
3
4
5
6 1package add
2
3import (
4 _ "go_dev/day2/example2/test"
5)
6
add.go
三、函数声明和注释
1.函数声明:func 函数名字(参数列表)(返回值列表){}
- 注释,两种注释,单行注释://和多行注释 /* */
四、常量和变量
1. 常量
-
(1). changliang使用const修饰,代表永远是只读的,不能修改
-
(2). const只能修饰boolean,number(int相关类型、浮点类型、complex)和string
-
(3). 语法:const identifier[type] = value,其中type可以省略
-
(4). 比较优雅的写法
1
2
3
4
5
6 1const (
2 a = 0
3 b = 1
4 c = 2
5)
6
-
(5). 更加专业的写法
1
2
3
4
5
6 1const (
2 a = iota
3 b // 1
4 c // 2
5)
6
练习
- 定义两个常量Man=1和Female=2,获取当前时间的秒数,如果能被Female整除,则在终端打印female,否则打印man。Second := time.Now().Unix()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 1package main
2
3import (
4 "fmt"
5 "time"
6)
7
8const (
9 Man = 1
10 Female = 2
11)
12
13func main() {
14 second := time.Now().Unix()
15 if second%Female == 0 {
16 fmt.Println("Female")
17 } else {
18 fmt.Println("Man")
19 }
20}
21
main.go
2、变量
(1). 语法:var identifier type
例1
1
2
3
4
5
6 1var a int
2var b string
3var c bool
4var d int = 8
5var e string = "hello world"
6
例2
1
2
3
4
5
6
7
8 1var (
2a int // 默认为0
3b string // 默认为“”
4c bool // 默认为false
5d = 8
6e = "hello world"
7)
8
练习
- 写一个程序获取当前运行的操作系统名称和PATH环境环境变量的值,并打印在终端。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 1package main
2
3import (
4 "fmt"
5 "os"
6)
7
8func get_os() {
9 go_os := os.Getenv("GOOS")
10 fmt.Printf("the operaing system is: %s\n", go_os)
11 path := os.Getenv("PATH")
12 fmt.Printf("Path is: %s\n", path)
13}
14
15func main() {
16 get_os()
17}
18
main.go
变量的作用域
-
1. 在函数内部声明的变量叫做局部变量,生命周期仅限于函数内部。
-
- 在函数外部声明的变量叫做全局变量,生命周期作用于整个包,如果是大写的,则作用于整个程序。
五、数据类型和操作符
1. 值类型和引用类型
-
值类型:变量直接存储值,内存通常在栈中分配
-
引用类型:变量存储的是一个地址,这个地址存储最终的值。内存通常在堆上分配。通过GC回收。
值类型:基本数据类型int、float、bool、string以及数组和struct
引用类型:指针、slice、map、chan等都是引用类型。
练习:
-
写一个程序用来打印值类型和引用类型变量到终端,并观察输出结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 1package main
2
3import "fmt"
4
5func main() {
6 a := 5
7 b := make(chan int, 1)
8
9 fmt.Println("a=", a)
10 fmt.Println("b=", b)
11
12}
13
14输出
15// a= 5
16// b= 0xc00003a070
17
- 写一个程序,交换两个整数的值。比如: a=3; b=4; 交换之后:a=4;b=3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 1package main
2
3import "fmt"
4
5var n int = 100
6
7/*
8赋值语句只能在函数中, 以下情况都会报错
9var a int
10a = 100
11或者
12a := 100
13*/
14
15func swap(a int, b int) {
16 tmp := a
17 a = b
18 b = tmp
19}
20
21func swap1(a int, b int) (int, int) {
22 return b, a
23}
24
25func swap2(a *int, b *int) {
26 // 改变的是地址指向的那片内存的值
27 tmp := *a
28 *a = *b
29 *b = tmp
30}
31
32func test() {
33 // 类型转换
34 var a int8 = 100
35 var b int16 = int16(a) // 赋值必须类型相同
36
37 fmt.Printf("a=%d, b=%d", a, b)
38}
39
40func main() {
41 first := 10
42 second := 20
43
44 // 方式一
45 swap(first, second) // copy的是first和second的变量值
46
47 fmt.Println("first=", first)
48 fmt.Println("second=", second)
49
50 // 方式二
51 a, b := swap1(first, second)
52
53 fmt.Println("a=", a)
54 fmt.Println("b=", b)
55
56 // 方式三
57 c, d := second, first
58
59 fmt.Println("c=", c)
60 fmt.Println("d=", d)
61
62 // 方式四
63 swap2(&first, &second) // copy的是first和second的地址
64
65 fmt.Println("first=", first)
66 fmt.Println("second=", second)
67
68 test()
69
70}
71
交换a和b的四种方式
2. 数据类型和操作符
- 数据类型
(1) bool类型,只能存true或false
(2) 相关操作符,!、&&、||
(3) 数字类型,主要有int、int8、int16、int32、int64、uint8、uint16、uint32、uint64、float32、float64
(4) 类型转换,type(variable),比如:var a int=8; var b int32=int32(a)
(5) 字符类型:var a byte = 'c'
(6) 字符串类型:var str string = "hello world"
注:字符串表示两种方式:
1)“” 双引号:支持转义字符,如\n, \t, %%等等
2)
1 | 1` ```` ` |
(反引号): 不支持转义字符,内容按原样输出
- 操作符
(1) 逻辑操作符:=、!=、<、<=、>和>=
(2) 数学操作复:+、-、*、/ 等等
练习
- 使用math/rand生成10个随机整数,10个小于100的随机整数以及10个随机浮点数?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 1package main
2
3import (
4 "fmt"
5 "math/rand"
6 "time"
7)
8
9func init() {
10 rand.Seed(time.Now().Unix())
11}
12
13func main() {
14
15 for i := 0; i < 10; i++ {
16 a := rand.Int()
17 fmt.Println(a)
18 }
19
20 for i := 0; i < 10; i++ {
21 a := rand.Intn(100)
22 fmt.Println(a)
23 }
24
25 for i := 0; i < 10; i++ {
26 a := rand.Float32()
27 fmt.Println(a)
28 }
29}
30
main.go
- 字符串两种表示方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 1package main
2
3import "fmt"
4
5func main() {
6 var str = "hello world\n"
7 var str1 = `
8 床前明月光,
9 疑是地上霜,
10 举头望明月,
11 低头思故乡。
12 `
13 var b byte = 'c'
14
15 fmt.Println(str)
16 fmt.Println(str1)
17 fmt.Println(b)
18 fmt.Printf("%c\n", b)
19}
20
21输出:
22hello world
23
24
25 床前明月光,
26 疑是地上霜,
27 举头望明月,
28 低头思故乡。
29
3099
31c
32
字符串两种表示方式
- 字符串逆转
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 1package main
2
3import "fmt"
4
5func reverse(str string) string {
6 var result string
7 strlen := len(str)
8 for i := 0; i < strlen; i++ {
9 result = result + fmt.Sprintf("%c", str[strlen-i-1])
10 }
11 return result
12}
13
14func reverse1(str string) string {
15 var result []byte
16 tmp := []byte(str)
17 length := len(str)
18 for i := 0; i < length; i++ {
19 result = append(result, tmp[length-i-1])
20 }
21 return string(result)
22}
23
24func main() {
25 str1 := "hello"
26 str2 := "world"
27
28 // str3 := str1 + " " + str2
29 str3 := fmt.Sprintf("%s %s", str1, str2)
30 n := len(str3)
31
32 fmt.Println(str3)
33 fmt.Printf("len(str3)=%d\n", n)
34
35 substr := str3[0:5]
36 fmt.Println(substr)
37
38 substr = str3[6:]
39 fmt.Println(substr)
40
41 result := reverse(str3)
42 fmt.Println(result)
43
44 result1 := reverse1(str3)
45 fmt.Println(result1)
46}
47
main.go
六、栈和堆
-
栈是在栈内存中分配的,公用的,性能最高, 堆是在系统内存中分配的
-
基本数据类型是在栈中存储的 引用数据类型是在堆中存储的
函数传参:做了一个拷贝,如果参数为变量值,则函数内部对变量做的操作不会影响实际变量的值。若传的参数为地址,则对地址指向变量的操作会影响实际变量的值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 1package main
2
3import "fmt"
4
5func modify(a int) {
6 a = 10
7 return
8}
9
10func modify1(a *int) {
11 *a = 10
12}
13
14func main() {
15 a := 5
16 b := make(chan int, 1)
17
18 fmt.Println("a=", a)
19 fmt.Println("b=", b)
20
21 modify(a) // 做了一个拷贝, 不影响原来的值
22 fmt.Println("a=", a)
23
24 modify1(&a) // 参数传了一个地址,对其指向的变量值进行操作会影响其地址指向的变量值
25 fmt.Println("a=", a)
26}
27
28// 栈是在栈内存中分配的,公用的,性能最高, 堆是在系统内存中分配的
29// 基本数据类型是在栈中存储的 引用数据类型是在堆中存储的
30
31/*
32a= 5
33b= 0xc00008c000
34a= 5
35a= 10
36*/
37
练习作业
-
- 判断 101-200 之间有多少个素数,并输出所有素数。
注:定义:为在大于1的自然数中,除了1和它本身以外不再有其他因数的数称为质数
-
- 打印出100-999中所有的“水仙花数”,所谓“水仙花数”是指一个三位数,其各位数字立方和等于该数本身。例如:153 是一个“水仙花数”,因为 153=1 的三次方+5 的三次方+3 的三次方。
-
- 对于一个数n,求n的阶乘之和,即: 1! + 2! + 3!+…n!
参考
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 1// 判断 101-200 之间有多少个素数,并输出所有素数。
2package main
3
4import (
5 "fmt"
6 "math"
7)
8
9func isPrime(n int) bool {
10 sqrt_n := int(math.Sqrt(float64(n))) + 1
11 for i := 2; i < sqrt_n; i++ {
12 if n%i == 0 {
13 return false
14 }
15 }
16 return true
17}
18
19func main() {
20 var n int
21 var m int
22
23 fmt.Printf("请输入两个数字:")
24 fmt.Scanf("%d%d", &n, &m)
25
26 for i := n; i < m; i++ {
27 if isPrime(i) == true {
28 fmt.Printf("%d\n", i)
29 }
30 }
31}
32
作业一
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 1/*
2 打印出100-999中所有的“水仙花数”,所谓“水仙花数”是指一个三位数,其各位数字立方和等于该数本身。
3例如:153 是一个“水仙花数”,因为 153=1 的三次方+5 的三次方+3 的三次方。
4*/
5
6package main
7
8import (
9 "fmt"
10 "strconv"
11)
12
13func isShuixianhua(n int) bool {
14 var i, j, k int
15 i = n % 10
16 j = (n / 10) % 10
17 k = (n / 100) % 10
18 sum := i*i*i + j*j*j + k*k*k
19 return sum == n
20}
21
22func isShuixianhua2(n int) bool {
23 var result = 0
24 str := strconv.Itoa(n)
25 for i := 0; i < len(str); i++ {
26 num := int(str[i] - '0')
27 result += (num * num * num)
28 }
29 number, err := strconv.Atoi(str)
30 if err != nil {
31 fmt.Printf("can not convert %s to int\n", str)
32 }
33 if result == number {
34 return true
35 }
36 return false
37}
38
39func main() {
40 var n int
41 var m int
42
43 fmt.Printf("请输入两个数字:")
44 fmt.Scanf("%d,%d", &n, &m)
45
46 for i := n; i <= m; i++ {
47 if isShuixianhua(i) == true {
48 fmt.Println(i)
49 }
50 }
51}
52
作业二
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 1// 对于一个数n,求n的阶乘之和,即: 1! + 2! + 3!+…n!
2
3package main
4
5import "fmt"
6
7func sum(n int) uint64 {
8 var s uint64 = 1
9 var sum uint64 = 0
10 for i := 1; i <= n; i++ {
11 s = s * uint64(i)
12 fmt.Printf("%d!=%d\n", i, s)
13 sum += s
14 }
15 return sum
16}
17
18func main() {
19 var n int
20
21 fmt.Printf("请输入一个数字:")
22 fmt.Scanf("%d", &n)
23
24 s := sum(n)
25 fmt.Println(s)
26}
27
作业三