Go Lang Study Notes 2
Views: 1165
Wrote on Jan. 7, 2021, 5:54 p.m.
匿名函数和闭包
变量的作用域
1. 全局作用域
2. 函数作用域
3. 语句块作用域
defer
defer延迟执行函数
defer先注册后执行(在函数即将要结束但还没有结束的时候执行)
多用来做一些资源回收类的工作。
func testDefer() {
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
fmt.Println("函数马上要结束了...")
}
func main() {
testDefer()
}
分金币
Method 1:
import (
"fmt"
"strings"
)
/*
50枚金币,分配给一下几个人:Matthew,Sarah,Augustus ,Heidi,Emilie,Peter,Giana,Adriano,Aaron,Elizabeth.
分配规则如下:
a.名字中包含e或者E:1枚金币
b.名字中包含i或者I:2枚金币
c.名字中包含o或者O:3枚金币
d.名字中包含u或者U:4枚金币
写一个程序,计算每个用户分到多少金币,以及最后剩余多少金币?
*/
var (
coins = 50
users = []string{"Matthew", "Sarah", "Augustus", "Heidi", "Emilie", "Peter", "Giana", "Adriano", "Aaron", "Elizabeth"}
distribution = make(map[string]int, len(users))
)
// 根据规则分发金币,返回剩余的金币数量
func dispatchCoin() int {
sum := 0
// 1. 遍历名字的切片
for _, name := range users {
// 2. 根据规则分发金币
if strings.Contains(name, "e") || strings.Contains(name, "E") {
distribution[name] = distribution[name] + 1
sum++
}
if strings.Contains(name, "i") || strings.Contains(name, "I") {
distribution[name] = distribution[name] + 2
sum = sum + 2
}
if strings.Contains(name, "o") || strings.Contains(name, "O") {
distribution[name] = distribution[name] + 3
sum = sum + 3
}
if strings.Contains(name, "u") || strings.Contains(name, "U") {
distribution[name] = distribution[name] + 4
sum = sum + 4
}
}
return coins - sum
}
func main() {
left := dispatchCoin()
fmt.Println("剩下: ", left)
for k, v := range distribution {
fmt.Println(k, v)
}
}
Method 2:
// 根据规则分发金币,返回剩余的金币数量
func dispatchCoin() int {
sum := 0
// 1. 遍历名字的切片
for _, name := range users {
// 2. 根据规则分发金币
for _, char := range name {
switch char {
case 'e', 'E':
distribution[name] = distribution[name] + 1
sum = sum + 1
case 'i', 'I':
distribution[name] = distribution[name] + 2
sum = sum + 2
case 'o', 'O':
distribution[name] = distribution[name] + 3
sum = sum + 3
case 'u', 'U':
distribution[name] = distribution[name] + 4
sum = sum + 4
}
}
}
return coins - sum
}
func main() {
left := dispatchCoin()
fmt.Println("剩下: ", left)
for k, v := range distribution {
fmt.Println(k, v)
}
}
指针
指针和地址有什么区别?
地址:就是内存地址(用字节来描述的内存地址)
指针:指针是带类型的。
&
和*
&
:表示取地址
*
:根据地址取值
func main() {
// var a int
// fmt.Println(a)
// b := &a // 取变量a的内存地址
// fmt.Printf("b=%v\n", b)
// fmt.Printf("type b :%T\n", b)
// c := "豪杰"
// fmt.Printf("&c=%v\n", &c)
// // b = &c //取c的内存地址不能赋值给b
// d := 100
// b = &d
// fmt.Println(b)
// // *取地址对应的值
// fmt.Println(*b)
// // 指针可以做逻辑判断
// fmt.Println(b == &d)
//指针的应用
a := [3]int{1, 2, 3}
modifyArray(a) //在函数中复制了数组赋值给了内部的a1
fmt.Println(a)
modifyArray2(&a)
fmt.Println(a)
}
// 定义一个修改数组第一个元素为100的函数
func modifyArray(a1 [3]int) {
a1[0] = 100 //只是修改的内部的a1这个数组
}
// 定义一个修改数组第一个元素为100的函数
// 接收的参数是一个数组的指针
func modifyArray2(a1 *[3]int) {
// (*a1)[0] = 100 //只是修改的内部的a1这个数组
//语法糖:因为Go语言中指针不支持修改
a1[0] = 100 //只是修改的内部的a1这个数组
}
new和make
new:是用来初始化值类型指针的
make:是用来初始化slice
、map
、 chan
// 以下是错误的写法
// var a *int //a是一个int类型的指针
// var b *string
// var c *[3]int
// 以上是错误的写法
var a = new(int) //得到一个int类型的指针
fmt.Println(a)
*a = 10
fmt.Println(a)
fmt.Println(*a)
var c = new([3]int)
fmt.Println(c)
c[0] = 1
fmt.Println(*c)
panic和recover
panic:运行时异常 recover:用来将函数在panic时恢复回来,用于做一些资源回收的操作 注意:程序会出现panic一定是不正常的。
func f1() {
defer func() {
// recover
err := recover() //尝试将函数从当前的异常状态恢复过来
fmt.Println("recover抓到了panic异常", err)
}()
var a []int
a[0] = 100 //panic
fmt.Println("panic之后")
}
// panic错误
func main() {
f1()
fmt.Println("这是main函数")
}
结构体(struct)和方法
type
关键字用来在Go语言中定义新的类型。
自定义类型和类型别名
自定义类型
创造一个新类型
// NewInt 是一个新的类型
type NewInt int
// 类型别名:只存在代码编写过程中,代码编译之后根本不存在haojie
// 提高代码的可读性
type haojie = int
// byte uint8
func main() {
var a NewInt
fmt.Println(a)
fmt.Printf("%T\n", a)
var b haojie
fmt.Println(b)
fmt.Printf("%T\n", b)
var c byte
fmt.Println(c)
fmt.Printf("%T\n", c)
}
类型别名(软链)
var MyInt = int
byte
: uint8 和 rune
:int32是Go语言内置的别名。
类型别名只在代码编写过程中生效,编译完不存在。
结构体的定义
type student struct {
name string
age int
gender string
hobby []string
}
func main() {
stu1 := student{
"琪琪",
10,
"女",
[]string{"吃", "喝", "玩", "乐"},
}
stu2 := &student{
name: "妙妙",
gender: "女",
}
fmt.Printf("%p\n", &stu1)
fmt.Printf("%p\n", stu2)
}
// 结构体
// 创在新的类型要使用type关键字
type student struct {
name string
age int
gender string
hobby []string
}
func main() {
var haojie = student{
name: "豪杰",
age: 19,
gender: "男",
hobby: []string{"篮球", "足球", "双色球"},
}
//结构体支持.访问属性
fmt.Println(haojie)
fmt.Println(haojie.name)
fmt.Println(haojie.age)
fmt.Println(haojie.gender)
fmt.Println(haojie.hobby)
// 实例化方法1
// struct是值类型的
// 如果初始化时没有给属性(字段)设置对应的初始值,那么对应属性就是其类型的默认值
var wangzhan = student{}
fmt.Println(wangzhan.name)
fmt.Println(wangzhan.age)
fmt.Println(wangzhan.gender)
fmt.Println(wangzhan.hobby)
// 实例化方法2 new(T) T:表示类型或结构体
var yawei = new(student)
fmt.Println(yawei)
// (*yawei).name
yawei.name = "亚伟"
yawei.age = 18
fmt.Println(yawei.name, yawei.age)
// 实例化方法3
var nazha = &student{}
fmt.Println(nazha)
nazha.name = "沙河娜扎"
fmt.Println(nazha.name)
//结构体初始化
//只填值初始化
var stu1 = student{
"豪杰",
18,
"男",
[]string{"男人", "女人"},
}
fmt.Println(stu1.name, stu1.age)
//键值对初始化
var stu2 = &student{
name: "豪杰",
gender: "男",
}
fmt.Println(stu2.name, stu2.age, stu2.gender)
}
结构体的实例化
- 基本实例化
go
var haojie = student{
name: "豪杰",
age: 19,
gender: "男",
hobby: []string{"篮球", "足球", "双色球"},
}
结构体的初始化
结构体的内存布局
了解为主
结构体的字段在内存上是连续的。
//结构体的内存布局
// 内存是以字节为单位的十六进制数
// 1字节 = 8位 = 8bit
func main() {
type test struct {
a int16
b int16
c int16
}
var t = test{
a: 1,
b: 2,
c: 3,
}
fmt.Println(&(t.a))
fmt.Println(&(t.b))
fmt.Println(&(t.c))
}
//结构体是一个值类型
type student struct {
name string
age int8
}
func main() {
var stu1 = student{
name: "豪杰",
age: 18,
}
stu2 := stu1 // 将结构体stu1的值完整的复制一份给了stu2
stu2.name = "王展"
fmt.Println(stu1.name)
fmt.Println(stu2.name)
stu3 := &stu1 //将stu1对应的地址赋值给了stu3,stu3的类型是一个*student
fmt.Printf("%T\n", stu3)
(*stu3).name = "娜扎"
fmt.Println(stu1.name, stu2.name, stu3.name)
}
构造函数
type student struct {
name string
age int
gender string
hobby []string
}
//自己实现一个构造函数
func newStudent(n string, age int, g string, h []string) *student {
return &student{
name: n,
age: age,
gender: g,
hobby: h,
}
}
func main() {
hobbySlice := []string{"篮球", "球"}
haojie := newStudent("豪杰", 18, "男", hobbySlice)
fmt.Println(haojie.name)
}
基于函数版学员信息管理系统
获取终端输入
需求分析
func main() {
var (
name string
age int
married bool
)
fmt.Println(name, age, married)
// fmt.Scan(&name, &age, &married)
// fmt.Scanf("name:%s age:%d married:%t\n", &name, &age, &married)
fmt.Scanln(&name, &age, &married)
fmt.Println(name, age, married)
// 1. 打印菜单
// 2. 等待用户输入菜单选项
// 3. 添加书籍的函数
// 4. 修改书籍的函数
// 5. 展示书籍的函数
// 6. 退出 os.Exit(0)
}
代码实现
package main
import (
"fmt"
"os"
)
// 需求
// 使用函数实现一个简单的图书管理系统。
// 每本书有书名、作者、价格、上架信息,
// 用户可以在控制台添加书籍、修改书籍信息、打印所有的书籍列表。
// 需求分析
// 0. 定义结构体
type book struct {
title string
author string
price float32
publish bool
}
// 定义创建新书的构造函数
func newBook(title, author string, price float32, publish bool) *book {
return &book{
title: title,
author: author,
price: price,
publish: publish,
}
}
//定义一个存放book指针的切片,用来存储所有的书籍
var allBooks = make([]*book, 0, 200)
// 1. 打印菜单
func showMenu() {
fmt.Println("欢迎登录BMS!")
fmt.Println("1. 添加书籍")
fmt.Println("2. 修改书籍信息")
fmt.Println("3. 展示所有书籍")
fmt.Println("4. 退出")
}
// 2. 等待用户输入菜单选项
// 定义一个专门用来获取用户输入的书籍信息的
func userInput() *book {
var (
title string
author string
price float32
publish bool
)
//3.1 获取用户输入
fmt.Println("请根据提示输入相关内容")
fmt.Print("请输入书名:")
fmt.Scanln(&title)
fmt.Print("请输入作者:")
fmt.Scanln(&author)
fmt.Print("请输入价格:")
fmt.Scanln(&price)
fmt.Print("请输入是否上架[true|false]:")
fmt.Scanln(&publish)
fmt.Println(title, author, price, publish)
//3.2 创建一本新书
book := newBook(title, author, price, publish)
return book
}
// 3. 添加书籍的函数
func addBook() {
book := userInput()
//3.3 把书添加到allBooks切片中
// 3.3.1 判断新增的书名是否已经存在
for _, b := range allBooks {
if b.title == book.title {
fmt.Printf("《%s》这本书已经存在了!", book.title)
return
}
}
allBooks = append(allBooks, book)
fmt.Println("添加书籍成功!")
}
// 4. 修改书籍的函数
func updateBook() {
book := userInput()
// 4.1 遍历所有的书籍根据书名找到要修改的那本书,把信息更新一下
for index, b := range allBooks {
// 如果便利到的这本书的书名正好等于book.title 就更新
if b.title == book.title {
allBooks[index] = book
fmt.Printf("书名:《%s》更新成功!\n", book.title)
return
}
}
fmt.Printf("书名:《%s》不存在!\n", book.title)
}
// 5. 展示书籍的函数
func showBooks() {
if len(allBooks) == 0 {
fmt.Println("啥也没有!")
return
}
for _, b := range allBooks {
fmt.Printf("《%s》 作者:%s 价格:%.2f 是否上架销售:%t\n", b.title, b.author, b.price, b.publish)
}
}
// 6. 退出 os.Exit(0)
func main() {
for {
showMenu()
// 2. 等待用户输入菜单选项
var option int
fmt.Scanln(&option)
switch option {
case 1:
addBook()
case 2:
updateBook()
case 3:
showBooks()
case 4:
os.Exit(0)
}
}
}
结构体的嵌套
结构体的匿名字段
//函数是谁都可以调用的。
//方法就是某个具体的类型才能调用的函数
type people struct {
name string
gender string
}
//函数指定接受者之后就是方法
// 在go语言中约定成俗不用this也不用self,而是使用后面类型的首字母的小写
func (p *people) dream() {
p.gender = "男"
fmt.Printf("%s的梦想是不用上班也有钱拿!\n", p.name)
}
func main() {
var haojie = &people{
name: "豪杰",
gender: "爷们",
}
// (&haojie).dream()
haojie.dream()
fmt.Println(haojie.gender)
}
什么时候应该使用指针类型
1, 需要修改接受者中的值
2, 接受者是拷贝代价比较大的大对象
3, 一般情况下通常都采用指针接受者
// 可以给任意类型追加方法
// 不能给别的包定义的类型添加方法
type MyInt int
func (m *MyInt) sayHi() {
fmt.Println("Hello MyInt~")
}
func main() {
var a MyInt
fmt.Println(a)
a.sayHi()
}
// 匿名字段
type student struct {
name string
string
int
}
func main() {
var stu1 = student{
name: "豪杰",
}
fmt.Println(stu1.name)
fmt.Println(stu1.string)
fmt.Println(stu1.int)
}
//结构体的嵌套
type address struct {
province string
city string
}
type email struct {
province string
}
type student struct {
name string
age int
address //嵌套了别的结构体
email //嵌入匿名结构体
}
func main() {
var stu1 = student{
name: "豪杰",
age: 18,
address: address{
province: "河北",
city: "雄安",
},
}
fmt.Println(stu1)
fmt.Println(stu1.name)
// fmt.Println(stu1.province) //匿名字段支持直接访问
fmt.Println(stu1.address.province) // 当匿名字段有冲突的时候必须显式调用
fmt.Println(stu1.email.province) // 当匿名字段有冲突的时候必须显式调用
}
// 结构体内嵌模拟“继承”
type animal struct {
name string
}
//定义一个动物会动的方法
func (a *animal) move() {
fmt.Printf("%s会动~\n", a.name)
}
//定义一个狗的结构体
type dog struct {
feet int
animal
}
//定义了一个狗的方法 wangwang
func (d *dog) wangwang() {
fmt.Printf("%s 在叫:汪汪汪~\n", d.name)
}
func main() {
var a = dog{
feet: 4,
animal: animal{
name: "旺财",
},
}
a.wangwang() //调用狗的方法
a.move() //调用动物的方法
}
import (
"encoding/json"
"fmt"
)
//json序列化
//Student 学生
// type Student struct {
// ID int
// Gender string
// Name string
// }
// Student 是一个结构体
//定义元信息:json tag
type student struct {
ID int `json:"id"`
Gender string `json:"gender"`
Name string `json:"name"`
}
func main() {
var stu1 = student{
ID: 1,
Gender: "男",
Name: "豪杰",
}
// 序列化:把编程语言里面的数据转换成 JSON 格式的字符串
v, err := json.Marshal(stu1)
if err != nil {
fmt.Println("JSON格式化出错啦!")
fmt.Println(err)
}
fmt.Println(v) //[]byte
fmt.Printf("%#v", string(v)) //把[]byte转换成string
// str := "{\"ID\":1,\"Gender\":\"男\",\"Name\":\"豪杰\"}"
// //反序列化:把满足JSON格式的字符串转换成 当前编程语言里面的对象
// var stu2 = &Student{}
// json.Unmarshal([]byte(str), stu2)
// fmt.Println(stu2)
// fmt.Printf("%T\n", stu2)
}
学生管理系统
import (
"fmt"
"os"
)
func displayMenu() {
fmt.Println("*************************")
fmt.Println("*欢迎使用统爷大学学生管理系统*")
fmt.Println("*************************")
fmt.Println("请选择以下操作")
fmt.Println("【1】添加学生")
fmt.Println("【2】修改学生")
fmt.Println("【3】删除学生")
fmt.Println("【4】显示学生")
fmt.Println("【5】退出系统")
}
type student struct {
name string
id int
age int
class string
}
func newStudent(name string, id, age int, class string) *student {
return &student{
name: name,
id: id,
age: age,
class: class,
}
}
func inputStudent() *student {
var (
name string
id int
age int
class string
)
fmt.Print("学生姓名:")
fmt.Scanln(&name)
fmt.Print("学生id:")
fmt.Scanln(&id)
fmt.Print("学生年龄:")
fmt.Scanln(&age)
fmt.Print("学生班级:")
fmt.Scanln(&class)
newStu := newStudent(name, id, age, class)
return newStu
}
type studentMgr struct {
allStudent []*student
}
func newStudentMgr() *studentMgr {
return &studentMgr{
allStudent: make([]*student, 0, 100),
}
}
func (s *studentMgr) addStu(stu *student) {
for _, v := range s.allStudent {
if v.name == stu.name {
fmt.Printf("%s同学已经存在\n", v.name)
return
}
}
s.allStudent = append(s.allStudent, stu)
}
func (s *studentMgr) editStu(stu *student) {
for k, v := range s.allStudent {
if v.name == stu.name {
s.allStudent[k] = stu
return
}
}
fmt.Printf("%s同学还未被录入", stu.name)
}
func (s *studentMgr) deleteStu(stu string) {
for k, v := range s.allStudent {
if v.name == stu {
s.allStudent = append(s.allStudent[:k], s.allStudent[k+1:]...)
return
}
}
fmt.Printf("%s同学还未被录入", stu)
}
func (s *studentMgr) listStu() {
if len(s.allStudent) != 0 {
for _, v := range s.allStudent {
fmt.Printf("%s, 年龄:%d, 学号:%d, 班级%s\n", v.name, v.age, v.id, v.class)
}
return
}
fmt.Println("还没有学生录入")
}
func main() {
stuMgr := newStudentMgr()
for {
displayMenu()
var userChoice int
fmt.Print("您要执行的操作是: ")
fmt.Scanln(&userChoice)
// fmt.Println(userChoice)
switch userChoice {
case 1:
enteredStu := inputStudent()
stuMgr.addStu(enteredStu)
case 2:
enteredStu := inputStudent()
stuMgr.editStu(enteredStu)
case 3:
var enteredStu string
fmt.Print("请输入需要删除的学生姓名:")
fmt.Scanln(&enteredStu)
stuMgr.deleteStu(enteredStu)
case 4:
stuMgr.listStu()
case 5:
os.Exit(0)
}
fmt.Println()
fmt.Println()
fmt.Println()
}
}