2396 字
12 分钟
base04-递归+结构体
base04-递归+结构体
递归
// 永远不要高估自己!
// 递归:函数自己调用自己!// 递归适合处理那种问题相同\问题的规模越来越小的场景// 递归一定要有一个明确的退出条件
// 3! = 3*2*1 = 3*2!// 4! = 4*3*2*1 = 4*3!// 5! = 5*4*3*2*1 = 5*4!
// 计算n的阶乘func f(n uint64) uint64 { if n <= 1 { return 1 } return n * f(n-1)}
// 上台阶的面试题// n个台阶,一次可以走1步,也可以走2步,有多少种走法。func taijie(n uint64) uint64 { if n == 1 { // 如果只有一个台阶就一种走法 return 1 } if n == 2 { return 2 } return taijie(n-1) + taijie(n-2)}
func main() { // ret := f(7) // fmt.Println(ret) ret := taijie(4) fmt.Println(ret)}02、type
// 自定义类型和类型别名// type后面跟的是类型type myInt int // 自定义类型type yourInt = int // 类型别名func main() { var n myInt n = 100 fmt.Println(n) fmt.Printf("%T %d\n", n, n)
var m yourInt m = 100 fmt.Println(m) fmt.Printf("%T\n", m)
var c rune c = '中' fmt.Println(c) fmt.Printf("%T\n", c)}03、结构体1
// 结构体type person struct { name string age int gender string hobby []string}
func main() { // 声明一个person类型的变量p var p person // 通过字段赋值 p.name = "周林" p.age = 9000 p.gender = "男" p.hobby = []string{"篮球", "足球", "双色球"} fmt.Println(p) // 访问变量p的字段 fmt.Printf("%T\n", p) fmt.Println(p.name) var p2 person p2.name = "理想" p2.age = 18 fmt.Printf("type:%T value:%v\n", p2, p2)
// 匿名结构体:多用于临时场景 var s struct { x string y int } s.x = "嘿嘿嘿" s.y = 100 fmt.Printf("type:%T value:%v\n", s, s)}04、结构体2
// 结构体是值类型type person struct { name, gender string}
// go语言中函数传参数永远传的是拷贝func f(x person) { x.gender = "女" // 修改的是副本的gender}
func f2(x *person) { // (*x).gender = "女" // 根据内存地址找到那个原变量,修改的就是原来的变量 x.gender = "女" // 语法糖,自动根据指针找对应的变量}
func main() { var p person p.name = "周林" p.gender = "男" f(p) fmt.Println(p.gender) // 男 f2(&p) // ox1241ac3 fmt.Println(p.gender) // 女 // 结构体指针1 var p2 = new(person) (*p2).name = "理想" p2.gender = "保密"
fmt.Printf("%T\n", p2) fmt.Printf("%p\n", p2) // p2保存的值就是一个内存地址 fmt.Printf("%p\n", &p2) // 求b2的内存地址 // 2. 结构体指针2 // 2.1 key-value初始化 var p3 = &person{ name: "元帅", } fmt.Printf("%#v\n", p3) // 2.2 使用值列表的形式初始化, 值的顺序要和结构体定义时字段的顺序一致 p4 := &person{ "小王子", "男", } fmt.Printf("%#v\n", p4)}05、 打印
//func main() { var a int a = 100 b := &a fmt.Printf("type a:%T type b:%T\n", a, b) // 将a的十六进制内存地址打印出来 fmt.Printf("%p\n", &a) fmt.Printf("%p\n", b) // b的值 fmt.Printf("%v\n", b) fmt.Printf("%p\n", &b) // b的内存地址}06、结构体
// 结构体占用一块连续的内存空间
type x struct { a int8 // 8bit => 1byte b int8 c int8}func main() { m := x{ a: int8(10), b: int8(20), c: int8(30), } fmt.Printf("%p\n", &(m.a)) fmt.Printf("%p\n", &(m.b)) fmt.Printf("%p\n", &(m.c))}07、 构造函数
// 构造函数type person struct { name string age int}
type dog struct { name string}
// 构造函数:约定成俗用new开头// 返回的是结构体还是结构体指针// 当结构体比较大的时候尽量使用结构体指针,减少程序的内存开销func newPerson(name string, age int) *person { return &person{ name: name, age: age, }}
func newDog(name string) dog { return dog{ name: name, }}
func main() { p1 := newPerson("元帅", 18) p2 := newPerson("周林", 9000) fmt.Println(p1, p2) d1 := newDog("周林") fmt.Println(d1)}08、方法是作用于特定类型的函数
// 方法
// 标识符:变量名 函数名 类型名 方法名// Go语言中如果标识符首字母是大写的,就表示对外部包可见(暴露的,公有的).
// dog 这是一个狗的结构体type dog struct { name string}
type person struct { name string age int}
func newPerson(name string, age int) *person { return &person{ name: name, age: age, }}
// 构造函数func newDog(name string) dog { return dog{ name: name, }}
// 方法是作用于特定类型的函数// 接受者表示的是调用该方法的具体类型变量,多用类型名首字母小写表示func (d dog) wang() { fmt.Printf("%s:汪汪汪~", d.name)}
// 使用值接收者:传拷贝进去// func (p person) guonian() {// p.age++// }
// 指针接收者:传内存地址进去func (p *person) zhenguonian() { p.age++}
func (p *person) dream() { fmt.Println("不上班也能挣钱!")}
func main() { // d1 := newDog("zhoulin") // d1.wang() p1 := newPerson("元帅", 18) // p1.wang() fmt.Println(p1.age) // 18 // p1.guonian() fmt.Println(p1.age) // 18 p1.zhenguonian() fmt.Println(p1.age) // ? p1.dream()}09、
// 给自定义类型加方法// 不能给别的包里面的类型添加方法,只能给自己包里的类型添加方法type myInt intfunc (m myInt) hello() { fmt.Println("我是一个int")}func main() { m := myInt(100) m.hello()}10、结构体遇到的问题
// 结构体遇到的问题
// 1. myInt(100)是个啥?type myInt int
func (m myInt) hello() { fmt.Println("我是一个int")}
type person struct { name string age int}
func main() { // 声明一个int32类型的变量x,它的值是10 // 方法1: // var x int32 // x = 10 // 方法2: // var x int32 = 10 // 方法3: // var x = int32(10) // 方法4: // x := int32(10) // fmt.Println(x)
// 声明一个myInt类型的变量m,它的值是100 // 方法1: // var m myInt // m = 100 // 方法2: // var m myInt = 100 // 方法3: // var m = myInt(100) // 方法4 // m := myInt(100) // 强制类型转换 // fmt.Println(m) // m := myInt(100) // m.hello()
// 问题2:结构体初始化
// 方法1:var p person // 声明一个person类型的变量pp.name = "元帅"p.age = 18fmt.Println(p) var p1 person p1.name = "周林" p1.age = 9000 fmt.Println(p1) // 方法2: s1 := []int{1, 2, 3, 4} m1 := map[string]int{ "stu1": 100, "stu2": 99, "stu3": 0, } fmt.Println(s1, m1)// 键值对初始化var p2 = person{ name: "冠华", age: 15,}fmt.Println(p2)// 值列表初始化var p3 = person{ "理想", 100,}fmt.Println(p3)}
// 问题3:为什么要有构造函数func newPerson(name string, age int) person { // 别人调用我,我能给她一个person类型的变量 return person{ name: name, age: age, }}
// func newPerson(name string, age int) *person {// // 别人调用我,我能给她一个person类型的变量// return &person{// name: name,// age: age,// }// }11、sms函数版
/* 函数版学生管理系统 写一个系统能够查看\新增学生\删除学生*/var ( allStudnet map[int64]*student // 变量声明)type student struct { id int64 name string}// newStudent 是student类型的构造函数func newStudent(id int64, name string) *student { return &student{ id: id, name: name, }}func showAllStudent() { // 把所有的学生都打印出来 for k, v := range allStudnet { fmt.Printf("学号:%d 姓名:%s\n", k, v.name) }}
func addStudent() { // 向allStudent中添加一个新的学生 // 1. 创建一个新学生 // 1.1 获取用户输入 var ( id int64 name string ) fmt.Print("请输入学生学号:") fmt.Scanln(&id) fmt.Print("请输入学生姓名:") fmt.Scanln(&name) // 1.2 造学生(调用student的构造函数) newStu := newStudent(id, name) // 2. 追加到allStudent这个map中 allStudnet[id] = newStu}
func deleteStudnet() { // 1. 请用户输入要删除的学生的序号 var ( deleteID int64 ) fmt.Print("请输入学生学号:") fmt.Scanln(&deleteID) // 2. 去allStudent这个map中根据学号删除对应的键值对 delete(allStudnet, deleteID)}
func main() { allStudnet = make(map[int64]*student, 48) // 初始化(开辟内存空间) for { // 1. 打印菜单 fmt.Println("欢迎光临学生管理系统!") fmt.Println(` 1. 查看所有学生 2. 新增学生 3. 删除学生 4. 退出 `) fmt.Print("请输入你要干啥:") // 2. 等待用户选择要做什么 var choice int fmt.Scanln(&choice) fmt.Printf("你选择了%d这个选项!\n", choice) // 3. 执行对应的函数 switch choice { case 1: showAllStudent() case 2: addStudent() case 3: deleteStudnet() case 4: os.Exit(1) // 退出 default: fmt.Println("滚~") } }}12、
// 匿名字段// 字段比较少也比较简单的场景// 不常用!!!
type person struct { string int}
func main() { p1 := person{ "周林", 9000, } fmt.Println(p1) fmt.Println(p1.string) fmt.Println(p1.int)}13、
// 结构体嵌套
type address struct { province string city string}
type workPlace struct { province string city string}
type person struct { name string age int address // 匿名嵌套结构体 workPlace // address:address}
type company struct { name string address}
func main() { p1 := person{ name: "周林", age: 9000, address: address{ province: "山东", city: "威海", }, } fmt.Println(p1) fmt.Println(p1.name, p1.address.city) // fmt.Println(p1.city) // 先在自己结构体找这个字段,找不到就去匿名嵌套的结构体中查找该字段 fmt.Println(p1.address.city) fmt.Println(p1.workPlace.city)}14、结构体模拟实现其他语言中的”继承”
// 结构体模拟实现其他语言中的"继承"
type animal struct { name string}
// 给animal实现一个移动的方法func (a animal) move() { fmt.Printf("%s会动!\n", a.name)}
// 狗类type dog struct { feet uint8 animal // animal拥有的方法,dog此时也有了【www.hlwnjl.com(互联网农家乐)下载免费程序员教程】}
// 给dog实现一个汪汪汪的方法func (d dog) wang() { fmt.Printf("%s在叫:汪汪汪~\n", d.name)}
func main() { d1 := dog{ animal: animal{name: "周林"}, feet: 4, } fmt.Println(d1) d1.wang() d1.move() // ?}15、 结构体与json
import ( "encoding/json" "fmt")// 结构体与json
// 1.序列化: 把Go语言中的结构体变量 --> json格式的字符串// 2.反序列化: json格式的字符串 --> Go语言中能够识别的结构体变量
type person struct { Name string `json:"name" db:"name" ini:"name"` Age int `json:"age"`}
func main() { p1 := person{ Name: "周林", Age: 9000, } // 序列化 b, err := json.Marshal(p1) if err != nil { fmt.Printf("marshal failed, err:%v", err) return } fmt.Printf("%v\n", string(b)) // 反序列化 str := `{"name":"理想","age":18}` var p2 person json.Unmarshal([]byte(str), &p2) // 传指针是为了能在json.Unmarshal内部修改p2的值 fmt.Printf("%#v\n", p2)}16、
17、