Go语言struct

1.初识结构体(struct)

参考李文周老师视频 https://www.liwenzhou.com/

package main

import "fmt"

//结构体
//解决的问题:没有办法在代码里表示具有多维度数据的个体

//构建一个person类型
type person struct {
	name string
	age int
	gender string
	hobby []string
}

func main()  {
	var p person //声明person类型变量
	p.name = "lf"
	p.age = 21
	p.gender = "nan"
	p.hobby = []string{"篮球","羽毛球"}
	fmt.Println(p)
	fmt.Printf("%T",p)

	
}

2.匿名结构体

/	匿名结构体:多用于临时场景
	//type定义类型 var 声明变量
	var s struct{
		name string
		age int
	}
	s.name = "lf"
	s.age = 21
	fmt.Println(s)
	fmt.Printf("%T",s)

结构体指针和结构体初始化

package main

import "fmt"

//结构体是值类型
type person struct {
	name,gender string //字段类型简写
}

//go语言函数传参永远是拷贝(副本)
func f(s person)  {
	s.gender = "男"
}
//传递指针地址
func f2(s *person)  {
	s.gender = "男"
}
func main()  {
	var p person
	p.name = "晓燕"
	p.gender = "女"
	f(p)
	fmt.Println(p)
	f2(&p)
	fmt.Println(p)

	//结构体指针1
	//还可以使用new关键字对结构体进行实例化,得到的是结构体的地址
	var p2 = new(person) //new(person)就是创建一个内存地址
	p2.name = "老男孩"

	fmt.Printf("%T\n",p2)
	fmt.Printf("%p\n",p2) //p2保存的值就是一个内存地址 比如"老男孩"的内存地址
	fmt.Println(&p2) //p2的内存地址

	//主要使用这种方式	结构体指针2 可以key-value,也可以省略key,顺序须一致
	var p3 = &person{
		"lf",
		"男",
	}
	fmt.Printf("%T\n",p3)
	fmt.Printf("%#v\n",p3)
	fmt.Println(&p3.name,&p3.gender)


}

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

//结构体占用一块连续的内存空间
type x struct {
	a int8
	b int8
	c string
}
func main()  {
	m := x{
		1,
		2,
		"3",
	}
	fmt.Println(&(m.a),&(m.b),&(m.c))
}

方法和接收者

Go语言中的方法(Method)是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者(Receiver)。接收者的概念就类似于其他语言中的this或者 self

方法的定义格式如下:

func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {
    函数体
}
type dog struct {
	name string
}
// 方法是作用域特定类型的函数
//接收者表示的是调用该方法的具体类型变量,多用类型首字母小写表示
func (d dog) wang()  {
	fmt.Println(d.name + "旺旺")
}
//构造函数
func newDog(name string)dog  {
	return dog{
		name,
	}
}
func main()  {
	d1 := newDog("lf")
	d1.wang()
}

值接收者和指针接收者的区别

package main

import "fmt"

//标识符:变量,变量名,函数名,方法名
//GO语言中标识符首字母是大写的,就表示对外部包可见(暴露的,公有的)
//type Dog struct
type dog struct {
	name string
}
type person struct {
	name string
	age int
}
// 方法是作用域特定类型的函数
//2.接收者表示的是调用该方法的具体类型变量,多用类型首字母小写表示
func (d dog) wang()  {
	fmt.Println(d.name + "旺旺")
}
//3.值接收和指针接收相差一个*
func (p *person) guonian()  {
	p.age ++
}
func (p *person) dream()  {
	fmt.Println("make money")
}
//1.构造函数
func newDog(name string)dog  {
	return dog{
		name,
	}
}
func newPeople(name string,age int)person  {
	return person{
		name,
		age,
	}
}
func main()  {
	d1 := newDog("lf")
	d1.wang()
	p1 := newPeople("lf",12)
	p1.guonian()
	fmt.Println(p1.age)
	p1.guonian()
	fmt.Println(p1.age)

	p1.dream()
}

任意类型添加方法

package main

import "fmt"

//给自定义类型添加方法
//不能给别的包里面的类型添加方法,只能给自己包里的类型添加方法
//如果一定要自定义,那么就自定义一个包就可以了
type myInt int

func (m myInt)hello()  {
	fmt.Println("I\"m int")
}
func main()  {
	m := myInt(100)
	m.hello()
}

函数版学生管理系统

package main

import (
	"fmt"
	"os"
)

//学生管理系统
/*
	函数版
	查看\新增\删除
*/
var (
	allStudent = make(map[int64]*student,50) //初始化(开辟内存空间)
)

type student struct {
	id int64
	name string

}

//student类型的构造函数
func newStudent(id int64,name string) *student {
	return &student{
		id,
		name,
	}
}

func showAllStudent(){
	//遍历所有学生
	for k,v := range allStudent{
		fmt.Printf("学号:%d  姓名:%s\n",k,v.name)
	}
}
func addStudent()  {
	//向allStudent中添加一个新的学生
	//1.创建一个新学生
	//1.1获取用户输入
	var (
		id int64
		name string
	)
	fmt.Println("请输入学生学号:")
	fmt.Scanln(&id)
	fmt.Println("请输入学生姓名:")
	fmt.Scanln(&name)

	//1.2创造一个学生()调用构造函数
	newStu := newStudent(id,name)
	//2.追加到allStudent map中
	allStudent[id] = newStu
}
func deleteStudent()  {
	//1.输入删除学生的学号
	var(
		deleteId int64
	)
	fmt.Println("请输入要删除学生学号:")
	//2.去allStudent这个map中根据学号删除对于键值对
	fmt.Scanln(&deleteId)
	delete(allStudent,deleteId)
}
func main()  {
	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:
			deleteStudent()
		case 4:
			os.Exit(1) //break仅能退出当前switch循环
		default:
			fmt.Println("滚~")
		}
	}
}

结构体的匿名字段和结构体嵌套

//匿名字段
//字段比较少而且简单 不常用
type person struct {
	string
	int
}

func main()  {
	p1 := person{
		"lf",
		10,
	}
	fmt.Println(p1.string)
	fmt.Println(p1.int)
}
package main

import "fmt"

//结构体嵌套

type address struct {
	province string
	city string
}

type workPlace struct {
	province string
	city string
}

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

type company struct {
	name string
	addr address
}
func main()  {
	p1 := person{
		"lf",
		21,
		address{
			"湖北",
			"武汉",
		},
		workPlace{
			"山东",
			"潍坊",
		},
	}
	//1. fmt.Println(p1.addr.province)
	//2. fmt.Println(p1.city) //先在自己结构体找这个字段,找不到就去匿名嵌套的结构体中查找该字段
	fmt.Println(p1.address.city) //匿名嵌套结构体冲突
}

模拟实现继承

package main

import "fmt"

//结构体模拟继承

type animal struct {
	name string

}

func (a animal) move()  {
	fmt.Println(a.name, "moving")
}

//dog 类
type dog struct {
	feet uint8
	animal //dog结构体把animal结构体完全包裹,animal拥有的方法dog也拥有
}

//给dog实现一个汪汪汪的方法
func (d dog) wang()  {
	fmt.Println(d.name,"wanging")
}
func main()  {
	d1 := dog{
		animal:animal{
			name:"yy",
		},
		feet: 4,
	}
	fmt.Println(d1)
	d1.wang()
	d1.move()
}


结构体与JSON

经常出现问题:

1.结构体内部的字段要大写!!!不大写别人访问不到

2.反序列化时要传递指针

package main

import (
	"encoding/json"
	"fmt"
)

//结构体与json

//	1.序列化:  go语言中的结构体变量 ->json格式的字符串()
//	2.反序列化:  json格式的字符串 -> Go语言能够识别的结构体变量

type person struct {
	//需要大写 json包拿不到小写的内容
	Name string `json:"name" db:"name" "ini":"name"`
	Age int `json:"age"`
}
func main()  {
	p1 := person{
		Name: "lf",
		Age: 21,
	}
	fmt.Println(p1)

	//go语言中的结构体变量 ->json格式的字符串()
	//json.Marshal(p1)
	b,err := json.Marshal(p1)
	if err != nil{
		fmt.Printf("marshal failed ,err %v",err)
		return
	}
	fmt.Println(string(b))

	//反序列化
	str := `{"Name":"lf","Age":21}`
	var p2 person
	//指针是为了能在json.Unmarshal内部修改p2的值
	json.Unmarshal([]byte(str),&p2)
	fmt.Printf("%#v\n",p2)
}



总结

package main

import (
	"encoding/json"
	"fmt"
)

type person struct {
	name string
	age int
}

//构造(结构体变量)函数
func newPerson(name string,age int) person  {
	return person{
		name,
		age,
	}
}

//方法
//接收者:使用对应类型的首字母小写
//指定了接收者之后,只有接收这个类型的变量才能调用这个方法
func (p person) dream(str string)  {
	fmt.Printf("%s的梦想是%s\n",p.name,str)
}

//*person 是内存地址,指针接收者
//1.需要修改结构体时的值要使用指针接收者
//2.结构体本身叫较大,拷贝的内存开销大时,使用指针接收者
//3.保持一致性:如果有一个方法使用了指针接收者,其它的方法为了统一也要使用指针接收者
func (p *person) guonian()  {
	p.age ++ //若是 p person 此处的p是副本
}
func main()  {
	var x int
	p := int(10)
	fmt.Println(x,p)


	var p1 person
	p1.name = "my"
	p1.age = 22

	p2 := person{ //结构体实例化
		"lf",
		21,
	}

	//调用构造函数生成perosn类型变量
	p3 := newPerson("帅哥",21)
	fmt.Println(p1,p2,p3)
	p2.dream("说话")
	p3.dream("打架")
	p3.guonian()
	fmt.Println(p3.age)

	//结构体嵌套
	type addr struct {
		province string
		city string
	}
	type student struct {
		name string
		addr  //匿名嵌套别的结构体
	}

	type point struct {
		X int `json:"x"`
		Y int `json:"y"`
	}
	pq := point{100,200}
	//序列化
	b,err := json.Marshal(pq)
	//如果出错了
	if err != nil{
		fmt.Printf("marshal failed,err:%v\n",err)
	}
	fmt.Println(string(b))

	// 反序列化
	str1 := `{"x":100,"y":200}`
	var ps point

	err = json.Unmarshal([]byte(str1),&ps)	//相当于修改ps的值,
	if err != nil{
		fmt.Printf("unmarshal failed,%v\n",ps)
	}
	fmt.Println(ps)
}

请添加图片描述

两两对应
请添加图片描述

定义方法
请添加图片描述

错误

请添加图片描述

结构体版学生管理系统

//main

package main

import (
	"fmt"
	"os"
)

//菜单函数
var smr studentManager //声明一个全局学生管理对象:smr

func showMenu()  {
	fmt.Println("-----------------welocme to sms!------------------")
	fmt.Println(
		`
	1.查看所以学生
	2.增加学生
	3.修改学生
	4.删除学生
	5.退出


		`)
}
func main()  {
	smr = studentManager{ //修改的全局的变量
		allStudent: make(map[int]student,100),
	}
	for{
		showMenu()
		//等待用户输入
		fmt.Println("请输入要执行的选项:")
		var choice int
		fmt.Scanln(&choice)
		fmt.Printf("你输入的是%v\n",choice)

		switch choice {
		case 1:
			smr.showStudnets()
		case 2:
			smr.addStudnets()
		case 3:
			smr.editStudnets()
		case 4:
			smr.deleteStudnets()
		case 5:
			os.Exit(1)
		default:
			fmt.Println("滚~")

		}

	}

}

//student_manager
package main

import "fmt"

//学生管理系统
//有一个物件:
//1.它保存了一些数据  --->结构体的字段
//2.它有三个功能		 --->结构体的方法


type student struct {
	id int
	name string
}

//造一个学生的管理者
type studentManager struct {
	allStudent map[int]student
}
//查看学生
func (s studentManager) showStudnets()  {
	//从s.allStudent这个map中把所有的学生逐个打印
	for _,stu := range s.allStudent{ //stu是每一个学生student
		fmt.Printf("学号:%d 姓名%s\n",stu.id,stu.name)
	}
}
//增加学生
	func (s studentManager) addStudnets()  {
	//1.根据用户输入的内容创建一个新的学生
	//2.把新的学生放到s.allstudent这个map中
	var (
		id int
		name string
	)
	//获取用户输入
	fmt.Println("请输入学号:")
	fmt.Scanln(&id)
	fmt.Println("请输入姓名:")
	fmt.Scanln(&name)
	//根据用户输入创建结构体对象
	newStu := student{
		id,
		name,
	}
	s.allStudent[newStu.id] = newStu
	fmt.Println("添加成功!")
}
//修改学生
func (s studentManager) editStudnets()  {
	var (
		id int
	)
	//1.获取用户输入的学号
	fmt.Println("请输入需要修改的学号:")
	fmt.Scanln(&id)
	//2.展示该学号对应的学生信息,如果没有提示查无此人
	stuObj,ok := s.allStudent[id]
	if !ok{
		fmt.Println("查无此人!")
		return
	}
	fmt.Printf("你要修改的学生信息如下:学号:%d  姓名:%s",stuObj.id,stuObj.name)
	//3.请输入修改后的学生名
	fmt.Println("请输入学生的新名字:")
	var newName string
	fmt.Scanln(&newName)
	//4.更新学生姓名
	stuObj.name = newName
	s.allStudent[id] = stuObj	//更新map中的学生
	//因为此处的student结构体并不是指针类型的,所以并不能直接 s.allStudent[id].name = newName来实现
	//s.allStudent[id].name = newName map元素为结构体时,用指针才能修改字段
}
//删除学生
func (s studentManager) deleteStudnets()  {
	//1.请用户输入要删除的学生id
	var (
		id int
	)
	//1.获取用户输入的学号
	fmt.Println("请输入需要删除的学号:")
	fmt.Scanln(&id)
	//2.去map里面找有没有这个学生,如果没有就打印查无此人,有的话就删除
	_,ok := s.allStudent[id]
	if !ok{
		fmt.Println("查无此人!")
		return
	}
	delete(s.allStudent,id)
	fmt.Println("删除成功!")
}
//var (
//	allStudent map[int64]student
//)

请添加图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值