这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
一、本堂课重点内容:
基础知识
- var
- for
- if
- switch
- array
- slice
- map
- range
- func
- struct
- struct-method
- error
- string
- json
- time
- strconv
- env
- image
- import
基础实践
- guessing-game 猜谜游戏
- simpledict 命令行词典
- proxy SOCKS5 代理
二、详细知识点介绍:
声明
- 当一个计算机程序需要调用内存空间时,对内存发出的“占位”指令,称为:“声明”。
- 从根本上说,静态类型和动态类型语言的最大区别就是,数据类型是否在编译时确定。
for 循环
for j := 7; j < 9; j++ {
// 循环体
}
- 初始赋值;循环条件;循环后加分 省略哪个都可以。
if 判断
if num := 9; num < 0 {
// false
} else if num < 10 {
// true
} else {
// false
}
- 初始赋值;判断条件 初始赋值可省略。
- 如果不满足,可接下来判断else。
switch 判断
a := 2
switch a {
case 1:
// 1
case 2:
// 2
case 3:
// 3
case 4, 5:
// 4,5
default:
// other
}
- 多种情况判断的语法。
array
- 数组的声明
// 创建一个[0:4] int类型的数组a
var a [5]int
- 数组下标赋值
a[4] = 100
- 数组下标的使用
fmt.Println("get:", a[2])
- 数组由于声明时需要固定大小,所以在go语言当中并不常用,slice更深得人心。
- 数组的索引从0开始,因此索引的取值范围应该是从0至数组元素个数减1为止。如本例则为0、1、2、3。超出范围的赋值和取值将引发下标越界错误,导致程序出错。对某一索引位置的元素重复赋值将导致旧值被新值替换。
slice
- 切片的声明
var s []int
// 上面是个空切片 当添加值时 会自动扩容
s := make([]string, 3)
- 添加切片的值 值得一提的是,append()函数本身并不会改变原有切片,只是将切片“扩容”后的结果作为函数返回值。因此,需要将“扩容”后的结果再次(即函数返回值)赋值给slice_name,才能真正使slice_name发生改变。
s = append(s, "d")
- 与数组不同,为切片赋值可以理解为“扩充”。在一开始,切片里面的元素个数为0。“扩充”一个值,就相当于为切片中的第一个元素赋值。赋值后,切片的元素个数就变成了1。若再次“扩充”,则相当于为切片中的第二个元素赋值。赋值后,切片的元素个数就变成了2,以此类推
map
- 集合的声明 集合可以看作是一类特殊的切片,只不过集合的元素都是由若干“键-值对”数据构成的。所谓“键”,相当于“唯一ID”;“值”,相当于单条数据,键不允许重复。
m := make(map[string]int)
- 值得一提的是,若对一个已经存在数据的“键”再次赋值,原有的数据将被覆盖。
range
nums := []int{2, 3, 4}
sum := 0
for i, num := range nums { // 求该值索引序号
sum += num // 求和
if num == 2 {
fmt.Println("index:", i, "num:", num) // index: 0 num: 2
}
}
- for循环仅适用于数组和切片的元素遍历
- for-range结构适用于数组、切片和集合
func
- 函数声明
func add(a int, b int) int {
return a + b
}
// 变量都是在各自的函数体内声明和使用的,无法共用,只是凑巧名称和类型都一样而已。大家不要将它俩混为一谈。
struct
- 结构体声明
type user struct {
name string
password string
}
- 结构体使用
func checkPassword(u user, password string) bool {
return u.password == password
}
func checkPassword2(u *user, password string) bool {
return u.password == password
}
- 值传递 直接传递一个变量名到另一个函数中,属于值传递。按照Go代码的执行策略,发生值传递时,将在另一个函数中自动生成一个值的副本。
- 引用传递 与值传递相对的便是引用传递,这种方式在函数间传递的是指针,而指针恰恰是内存地址。这样的传值,无论发生在多少个函数之间,改变将始终作用于相同地址的数据上。
struct-method
- 结构体方法声明
func (u user) checkPassword(password string) bool {
return u.password == password
}
func (u *user) resetPassword(password string) {
u.password = password
}
error
string
a := "hello"
fmt.Println(strings.Contains(a, "ll")) // true
fmt.Println(strings.Count(a, "l")) // 2
fmt.Println(strings.HasPrefix(a, "he")) // true
fmt.Println(strings.HasSuffix(a, "llo")) // true
fmt.Println(strings.Index(a, "ll")) // 2
fmt.Println(strings.Join([]string{"he", "llo"}, "-")) // he-llo
fmt.Println(strings.Repeat(a, 2)) // hellohello
fmt.Println(strings.Replace(a, "e", "E", -1)) // hEllo
fmt.Println(strings.Split("a-b-c", "-")) // [a b c]
fmt.Println(strings.ToLower(a)) // hello
fmt.Println(strings.ToUpper(a)) // HELLO
fmt.Println(len(a)) // 5
json
time
now := time.Now()
fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
fmt.Println(t) // 2022-03-27 01:25:36 +0000 UTC
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25
fmt.Println(t.Format("2006-01-02 15:04:05")) // 2022-03-27 01:25:36
diff := t2.Sub(t)
fmt.Println(diff) // 1h5m0s
fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900
t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36")
if err != nil {
panic(err)
}
fmt.Println(t3 == t) // true
fmt.Println(now.Unix()) // 1648738080
strconv
env
image
import
三、实践练习例子:
guessing-game 猜谜游戏
simpledict 命令行词典
proxy SOCKS5 代理
四、课后个人总结:
- 本章有什么知识点不容易掌握?
- 什么地方容易与其他内容混淆?