--图片来自b站up: @微光捉影
golang
1. go程序开发和基本结构
package main // 表示该hello.go文件所在的包是main,在go中,每个文件都必须归属于一个包。
import "fmt"
表示:引入一个包,包名fmt,引入该包后,就可以使用fmt包的函数,比如: fmt.Println
func 是一个关键字,表示一个函数。 main 是函数名,是一个主函数,即我们程序的入口。
编译与执行 -- 两种执行流
1.先编译后执行 : .go(源文件) --编译--> .exe --运行--> 结果
通过go build命令对该go文件进行编译,生成.exe文件,将exe文件拷贝到没有go sdk的机器也可以运行该exe文件 语法: go build (-o 生成的可执行文件名.exe ) 源文件名.go 不指定exe文件名时默认与源文件test同名
eg: go build test.go
go build -o mytest.exe test.go
然后目录下有两个exe文件 mytest.exe 和 test.exe
在dos命令行下执行.exe文件就可以看到运行效果. eg:
test.exe
2.直接 go run 运行: 编译运行一起,但不生成.exe文件 不能再没有 go sdk 的机器上运行
通过 go run 命令可以直接运行 hello.go 程序(类似执行一个脚本文件的形式),但是在实际开发中肯定是先编译再运行
- 注意事项:
Go方法由一条条语句构成,每个语句后可以不加分号(Go语言会在每行后自动加分号) Go编译器是一行行进行编译的,因此一行就写一条语句,不能把多条语句写在同一个,否则报错 go语言定义的变量或者import的包如果没有使用到,代码不能编译通过。
2.循环和分支
类似c语言,但是if,switch,for后没有(),且循环体不能与for写在同一行 switch的case不用break,执行完一条会自动break,而且case的变量可以是任意类型不再局限于整形,甚至可以用switch case来写if-else语句
// 这里我们不需要switch的“表达式”,因为我们只是根据条件进行操作,而不需要比较变量或执行其他操作
var t = time.Now()
switch {//switch后面不需要变量
case t.Hour() < 12:
fmt.Print("没到12点")
default:
fmt.Print("过了12点")
}
defer 语句会将函数推迟到外层函数返回之后执行。 推迟调用的函数其参数会立即求值,但直到外层函数返回前该函数都不会被调用。 推迟的函数调用会被压入一个栈中。当外层函数返回时,被推迟的函数会按照后进先出的顺序调用。
fmt.Println("counting")
for i := 0; i < 10; i++ {
defer fmt.Println(i)
}
fmt.Println("done")
// 先打印conting done 然后打印 9~0
3.切片
切片是一种动态数组(类似cpp的vector),可以根据需要动态增加或减少元素的大小。切片是基于数组的,但与数组不同,它的长度不是固定的。
语法 : var slice []T , T 是切片存储元素的数据类型 (与数组不同,不用指定大小)。
也可以使用 make 函数创建切片:
slice := make([]T, len, cap) , T 是切片存储元素的数据类型,len 是切片的长度,cap 是切片的容量。长度是指切片中的元素个数,而容量是指切片底层数组中的元素个数。
// 切片也可以通过下标访问:
nums1 := []int{1, 2, 3, 4, 5}
fmt.Println(nums1[0]) // 输出:1
fmt.Println(nums1[1:3]) // 输出:[2 3]
// 在切片中添加元素时,如果没有超过切片的容量,则添加的元素将直接追加到切片的末尾。例如,以下代码向一个整数切片中添加了两个元素:
nums2 := []int{1, 2, 3, 4, 5}
nums2 = append(nums2, 6, 7)
fmt.Println(nums2) // 输出:[1 2 3 4 5 6 7]
// 如果添加的元素超过了切片的容量,则 Golang 会自动创建一个新的底层数组,并将原有的元素复制到新的底层数组中。
/*************** map ***************/
//map[keyType] valueType
m := make(map[string]int) //make创建一个空map
m["one"] = 1
m["two"] = 2
fmt.Println(m) // map[one:1 two:2]
fmt.Println(len(m)) //2
fmt.Println(m["one"]) //1
fmt.Println(m["unknow"]) //0 不存在的key它的value默认为0
r, ok := m["unknow"] //返回两个值 value和一个表示key是否存在的bool类型
fmt.Println(r, ok)// 0 false
p, _ := m["one"]//不需要这个bool也可用 _ 来接收或者只用一个p
fmt.Println(p) // 1
delete(m, "one")
m2 := map[string]int {"one": 1, "two": 2} //创建时初始化
fmt.Print(m2)
4. range 语法与使用
nums := []int{2, 3, 4}
sum := 0
for i, num := range nums { //用range来快速遍历 返回两个值 下标和它对应的值
sum += num
if num == 2 {
fmt.Println("index:", i, "num:", num) // index: O num: 2
}
}
5. 函数
// func 函数名 (参数列表) 返回值列表 然后是{}括起来的函数体
// go的函数通常都返回多个值 一个是真正的返回值另一个是错误信息 error
func exists(m map[string]string, k string) (v string, ok bool) {
v, ok = m[k]
return v, ok
}
func main() {
v, ok := exists(map[string]string{"a": "A"}, "a")
fmt.Println(v, ok) // A True
}
6.结构体
// 结构体 类似c语言 语法: type 结构体名 struct { 成员 }
type user struct {
name string
password string
}
func checkPassword(u user, password string) bool {
fmt.Print("普通函数 ")
return u.password == password
}
// 参数 u user 放到函数名前面 将它变成了一个类成员函数 !!!
func (u user) checkPassword(password string) bool {
fmt.Print("类成员函数 ")
return u.password == password
}
// 地址传参
func (u *user) resetPassword(password string) {
u.password = password
}
// 接收user结构体数组
func findUser(users []user, name string) (v *user, err error) {
for _, u := range users { //遍历
if u.name == name {
return &u, nil
}
}
return nil, errors.New("not found")
}
func main() {
a := user{name: "wang", password: "1024"}
a.resetPassword("2048")
fmt.Println(a.checkPassword("2048")) // 类成员函数 true
fmt.Print(checkPassword(a, "1024")) // 普通函数 false
/************************ 错误信息处理 errors包 ************************************/
u, err := findUser([]user{{"wang", "1024"}}, "wang")
if err != nil { //错误信息存在
fmt.Println(err)
return
}
fmt.Println(u.name) // wang
if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
fmt.Println(err) // not found
return
} else {
fmt.Println(u.name)
}
}
7. 字符串
///////////////////////// 字符串格式化 ////////////
type point struct {
x, y int
}
func main() {
s := "hello"
n := 123
p := point{1, 2}
fmt.Println(s, n) // hello 123
fmt.Println(p) // {1 2}
//类似c语言的格式控制字符 但是比c更简单 用 %v 可以打印任意类型变量
fmt.Printf("s=%v\n", s) // s=hello
fmt.Printf("n=%v\n", n) // n=123
fmt.Printf("p=%v\n", p) // p={1 2}
// %+v %#v 让打印的结果更详细
fmt.Printf("p=%+v\n", p) // p={x:1 y:2} 打印出对应字段的信息
fmt.Printf("p=%#v\n", p) // p=main.point {x:1, y:2} 对应字段和包名
f := 3.141592653
fmt.Println(f) //3.141592653
fmt.Printf("%.2f\n", f) // 3.14 控制小数点的方法跟C一样
}
8. json处理
import (
"encoding/json"
"fmt"
)
// golang中json操作 只需要结构体的全部字段都用大写字母开头( 表示公开变量)即可
type userInfo struct {
Name string
Age int `json:"aaa"` //在字段后加json的tag 可以使序列号后的字符串输出时按tag输出该字段
Hobby []string
}
func main() {
a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
// 用json.Marshal 序列化 得到一个字符串
buf, err := json.Marshal(a)
//错误处理, 如果 err 不为 nil,即立即停止当前操作,并向上抛出一个异常。
if err != nil {
panic(err)
}
// 打印出序列号后的字符串 前面记得加上string 不然打印的是16进制字符
//fmt.Println(buf) // [123 34 78 97...]
fmt.Println(string(buf)) // {"Name2:"wang","aaa":18,"Hobby":["Golang","TypeScript"])
buf, err = json.MarshalIndent(a, "", "\t")
if err != nil {
panic(err)
}
var b userInfo
// 反序列化
err = json.Unmarshal(buf, &b)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", b) // main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}}
}
9. 时间处理
import (
"fmt"
"time"
)
func main() {
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
}
10.结尾
感觉写的不太全,字节的基础课就讲了这些,30min的课看了我好久,讲的有点快,而且没有特别详细,毕竟才30min嘛。 另外还删了一些东西,因为笔记好像代码部分不能超过70%,但我大多都是代码样例,然后通过注释来理解。
最后,这篇笔记也是自己为了加深自己的印象而写的,等学完了再补充吧... over~