golang基础语法(1)| 青训营笔记

115 阅读2分钟

--图片来自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.结尾

20230506_154832199_iOS.png

感觉写的不太全,字节的基础课就讲了这些,30min的课看了我好久,讲的有点快,而且没有特别详细,毕竟才30min嘛。 另外还删了一些东西,因为笔记好像代码部分不能超过70%,但我大多都是代码样例,然后通过注释来理解。

最后,这篇笔记也是自己为了加深自己的印象而写的,等学完了再补充吧... over~