Go 基础之结构体

Go 5

递归函数

package main

import "fmt"

// 递归函数,一定要有一个明确的退出条件

// 计算n的阶乘
func f1(n int) int {
	if n > 0 {
		res := n * f1(n-1)
		return res
	} else {
		return 1
	}

}

// 台阶有n阶,一个人上台阶,可以一次上1阶,可以一次上2阶,也可以一次上3阶,问上这个n级的台阶一共有多少种走法?

func fx(n int) int {
	switch {
	case n == 1:
		return 1
	case n == 2:
		return 2
	case n == 3:
		return 4
	case n >= 4:
		return fx(n-1) + fx(n-2) + fx(n-3)
	default:
		return 0
	}

}

func main() {
	// fmt.Println(f1(3)) // 5*4*3*2
	fmt.Println(fx(5))
}

type

// 自定义类型和类型别名

type myint int     // 自定义类型
type yourint = int // 类型别名

func main() {
	var n myint
	n = 100
	fmt.Println(n)
	fmt.Printf("%T\n", n)

	c := "中"
	d := '中'
	fmt.Println(c, d)
	fmt.Printf("%T--%T\n", c, d)
}

结构体(struct)

package main

import "fmt"

// 结构体

type mytp struct {
	t1 int
	t2 string
	t3 []int
}

type person struct {
	name   string
	age    int
	gender string
	hobby  []string
	tt     mytp
}

func main() {
	// 声明一个person类型的p
	var p1 person
	// 通过字段去赋值
	p1.name = "hina"
	p1.age = 18
	p1.gender = "男"
	p1.hobby = []string{"唱", "跳", "rap", "篮球"}
	p1.tt.t1 = 111
	p1.tt.t2 = "xixix"
	p1.tt.t3 = []int{1, 2, 3}
	fmt.Println(p1)
}


匿名结构体

	// 匿名结构体:多用于临时场景
	var s struct {
		x string
		y int
	}
	s.x = "xxx"
	s.y = 111
	fmt.Printf("%T---%v\n", s, s)

结构体指针

package main

import (
	"fmt"
)

type person struct {
	name, gender string
}

// Go语言中函数参数永远是拷贝
func f(x person) {
	x.gender = "ffff" // 修改的是副本的gender
}

func f2(x *person) {
	// (*x).gender = "ffff" // 修改那个内存地址的变量的值
	x.gender = "ffff" // 语法糖,Go中不能对指针做操作,所有会自动添加*x
}

func main() {
	// var p person
	// p.name = "hina"
	// p.gender = "male"
	// f(p)
	// fmt.Println(p)
	// f2(&p)
	// fmt.Println(p)

	// 结构体指针一
	// var p2 = new(person)
	// fmt.Printf("%T\n", p2)
	// fmt.Printf("%p\n", p2)  // p2保存的值就是一个内存地址
	// fmt.Printf("%p\n", &p2)  // p2的内存地址

	// 结构体指针二
	// 2.1 key-value初始化
	var p3 = &person{
		name:   "hii",
		gender: "xxx",
	}
	fmt.Printf("%#v\n", p3)

	// 2.2使用值列表的形式初始化,值得顺序要和结构体定义时字段顺序一致
	p4 := &person{
		"hnnn",
		"ffff",
	}
	fmt.Printf("%#v\n", p4)
}

结构体占用连续内存

package main

import "fmt"

// 结构体占用一块连续的内存空间

type x struct {
	// a int8 // 8bits = 1bytes
	// b int8
	// c int8
	a, b, c int8
	d       string
}

func main() {
	m := x{
		a: int8(10),
		b: int8(20),
		c: int8(30),
		d: "hina",
	}
	fmt.Printf("%p\n", &m.a)
	fmt.Printf("%p\n", &m.b)
	fmt.Printf("%p\n", &m.c)
	fmt.Printf("%p\n", &m.d)
}

构造函数:返回一个结构体变量的函数

结构体是值类型,赋值的时候都是拷贝

package main

import "fmt"

// 构造函数

type person struct {
	name string
	age  int
}

// 构造函数
// 返回的是结构体还是结构体指针
// 当结构体比较大的时候尽量使用结构体指针,减少程序的内存消耗
func newperson(name string, age int) *person {
	return &person{
		name: name,
		age:  age,
	}
}

func main() {
	p1 := newperson("hina", 20)
	p2 := newperson("rui", 14)
	fmt.Println(p1, p2)
}

方法

package main

import "fmt"

type dog struct {
	name string
}

func newdog(name string) dog {
	return dog{
		name: name,
	}
}

// 方法是作用域特定类型的函数
// 接受者表示的是调用该方法的具体类型变量,多用类型名首字母小写表示
// 不使用*的话会将d的一个复制体传过来
func (d dog) wang() {
	fmt.Printf("%p\n", &d)
	fmt.Printf("%s:www\n", d.name)
}

func main() {
	d1 := newdog("zzz")
	fmt.Printf("%p\n", &d1)
	d1.wang()
}

值接受者和指针接受者

拷贝和传递的意思

image

什么时候需要使用指针接受者

  1. 需要修改接受者中的值
  2. 接受者占用内存太大
  3. 保证一致性,如果有某个方法使用了指针接受者,那么其他方法也应该使用指针接受者

给自定义类型加方法(给int加方法)

package main

import "fmt"

// 给自定义类型加方法
// 不能给别的包里的类型添加方法,只能给自己的包里加

type myInt int

func (m myInt) hello() {
	fmt.Println("我是一个int")
}

func main() {
	m := myInt(100)
	m.hello()
}

结构体常见问题

package main

import "fmt"

type person struct {
	name string
	age  int
}

func main() {
	// 结构体初始化

	var p person // 声明一个person的变量p
	p.name = "hina"
	p.age = 18
	fmt.Println(p)

	// 值键值对初始化
	p1 := person{
		name: "rui",
		age:  18,
	}
	fmt.Println(p1)

	p2 := newperson("lem", 12)
	fmt.Println(p2)

	p3 := newperson1("emt", 13)
	fmt.Println(p3)
}

func newperson(name string, age int) person {
	return person{
		name: name,
		age:  age,
	}
}

func newperson1(name string, age int) *person {
	return &person{
		name: name,
		age:  age,
	}
}

结构体的匿名字段

package main


// 匿名字段
// 字段比较少也比较简单的常见
// 不常用!!!
type person struct {
	string
	int
}

func main() {

	p1 := person{
		"hina",
		14,
	}

}

嵌套结构体

匿名嵌套结构体

package main

import "fmt"

// 嵌套结构体

type address struct {
	addr, city string
}

type workplace struct {
	addr, city string
}

type person struct {
	name    string
	age     int
	address // 匿名嵌套结构体
	// workplace  
}

type conpany struct {
	name string
	address
}

func main() {
	p1 := person{
		name: "hina",
		age:  18,
		address: address{
			addr: "江苏",
			city: "南京",
		},
	}
	fmt.Println(p1)
	fmt.Println(p1.name, p1.address.addr, p1.address.city)
	fmt.Println(p1.city) // 现在自己结构体找这个字段,找不到就去匿名嵌套的结构体的字段
}

匿名嵌套结构体的字段冲突

将字段写全

结构体的继承

package main

import "fmt"

// 结构体模拟实现其他语言的继承

type animal struct {
	name string
}

// 给animal实现一个动的方法
func (a *animal) move() {
	fmt.Printf("%s会动\n", a.name)
}

// dog类
type dog struct {
	feet   int8
	animal // animal拥有的属性和方法dog全都有
}

// 给dog实现叫的方法
func (d *dog) wang() {
	fmt.Printf("%s:汪汪汪~\n", d.name)
}

func main() {
	d1 := dog{
		feet: 4,
		animal: animal{
			name: "teddy",
		},
	}
	fmt.Println(d1)
	d1.wang()
	d1.move()
}

结构体与json

package main

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: "hina",
		Age:  18,
	}

	// 序列化
	b, err := json.Marshal(p1)
	if err != nil {
		fmt.Printf("序列化错误,%s\n", err)
		return
	}
	fmt.Println(string(b))
	// fmt.Printf("%#v\n", string(b))

	// 反序列化
	str := `{"name":"lem","age":111}`
	var p2 person
	json.Unmarshal([]byte(str), &p2) // 传指针是为了能在函数内部去修改p2的值
	fmt.Printf("%#v\n", p2)
}

函数版学生信息管理系统

package main

import (
	"fmt"
	"os"
)

/*
学生管理系统
写一个系统能够查看\新增\删除\编辑学生
*/

type student struct {
	id   int64
	name string
}

func main() {
	for {
		// 1.打印菜单
		fmt.Println("学生管理系统")
		fmt.Println(`
	0. 退出
	1. 查看所有学生
	2. 新增学生
	3. 删除学生

	`)
		fmt.Println("请输入指令:")
		// 2.等待用户选择
		var choice int
		fmt.Scanln(&choice)
		// fmt.Println(choice)
		// 3.执行对应的函数
		switch choice {
		case 1:
			showstu()
		case 2:
			addstu()
		case 3:
			delstu()
		case 0:
			os.Exit(1) // 退出、break退出的是switch
		default:
			fmt.Println("无效指令")
		}
	}
}

var (
	allstu = make(map[int64]*student) // 初始化(开辟内存空间)
)

func newstu(id int64, name string) *student {
	return &student{
		id:   id,
		name: name,
	}
}

func showstu() {
	for k, v := range allstu {
		fmt.Printf("学号:%d,姓名:%s\n", k, v.name)
	}
}

func addstu() {
	var (
		id   int64
		name string
	)
	fmt.Println("请输入学生的学号")
	fmt.Scanln(&id)
	fmt.Println("请输入学生的姓名")
	fmt.Scanln(&name)
	stu := newstu(id, name)
	allstu[id] = stu

}

func delstu() {
	fmt.Println("请输入要删除的学号:")
	var sid int64
	fmt.Scanln(&sid)
	delete(allstu, sid)
	fmt.Println("删除成功")
}

posted @ 2021-05-10 10:52  橘丶阳菜  阅读(97)  评论(0编辑  收藏  举报