go语言(函数、闭包、defer、panic/recover,递归,结构体,json序列化与反序列化)

函数

函数定义

格式:

func 函数名(参数)(返回值){
    函数体
}
声明函数:这里是指定参数的
func ChenYuJia(a int, b int) (int,int) {
	if a == 0 || b ==0 {
		return 0,0
	} else {
		return a * b, a+b
	}
}

测试代码:


func main() {
	resC, resJ :=count.ChenYuJia(1,2)
	fmt.Println(resC)
	fmt.Println(resJ)
}
可变参数
func Sum(x ...int) int{

	sum :=0;
	for _, i:= range x {
		sum+=i
	}
	return sum
	}

//不需要指定返回的数据
func Sum2(x ...int) (res int){
	sum :=0;
	for _, i:= range x {
		sum+=i
	}
	//直接return
	return
}

测试:

	//这里的传参是一个切片
	resS:=count.Sum(1,2)
	fmt.Println(resS)
定义函数类型
//定义
type calculation func(int, int) int


func main() {
	var c = add
	fmt.Println(c(1,2))

}
//add其实就是calculation 
func add(x, y int) int {
	return x + y
}

参数是函数

func main() {
	re := calc(1,2,add)
	fmt.Println(re)

}

func add(x, y int) int {
	return x + y
}
//传入指定的函数
func calc(x, y int, op func(int, int) int) int {
	return op(x, y)
}

defer语句

defer语句会将其后面跟随的语句进行延迟处理。在defer归属的函数即将返回时,将延迟处理的语句按defer定义的逆序进行执行,也就是说,先被defer的语句最后被执行,最后被defer的语句,最先被执行。

	fmt.Println("start")
	defer fmt.Println(1)
	defer fmt.Println(2)
	defer fmt.Println(3)
	fmt.Println("end")
}

结果:
start
end
3
2
1
由于defer语句延迟调用的特性,所以defer语句能非常方便的处理资源释放问题。比如:资源清理、文件关闭、解锁及记录时间等。

panic/recover

使用panic/recover模式来处理错误。 panic可以在任何地方引发,但recover只有在defer调用的函数中有效

func main() {
	
	funC()
}

func funC(){
	panic("急啊急啊急啊就")
}

结果:
在这里插入图片描述
recover()必须搭配defer使用。
defer一定要在可能引发panic的语句之前定义

func funcB() {
	defer func() {
		err := recover()
		//如果程序出出现了panic错误,可以通过recover恢复过来
		if err != nil {
			fmt.Println("recover in B")
		}
	}()
	panic("panic in B")
}

结果:
recover in B

递归

递归适合问题相同,问题规模越来越小的情况。例如:对某个数的阶乘

func main() {

	res :=funcB(5)
	fmt.Println(res)
}

func funcB(a int) int{
	if a <=0{
		return 0
	}else {
		return a + funcB(a -1)
	}

}

结构体

Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性。

定义

type 类型名 struct {
字段名 字段类型
字段名 字段类型

}

type person struct {
	name string
	sex string
	age  int
	hobby []string
}
var p person

	p.age = 12
	p.name = "占山"
	p.hobby = []string{"球","游戏"}
	fmt.Println(p)
	fmt.Println(p.name)

结构体指针

go语言中传入某个参数,都是值拷贝

func  xiugai(p person)  {
	//这里修改的是副本
	p.name = "王五"
}

打印的结果不变。
需要改值的要要用指针。

func main() {

	var p person
	p.age = 12
	p.name = "占山"
	p.hobby = []string{"球","游戏"}
	fmt.Println(p)
	fmt.Println(p.name)
	xiugai(&p)
	fmt.Println(p)
}

func  xiugai(p *person)  {
	//这里修改的是副本
	p.name = "王五"
}

结构体初始化

	p1 :=person{
		name: "哈哈",
		age: 2,
		hobby: []string{"球","game"},
	}
	fmt.Println(p1)

给结构体加构造函数

func main() {


	p := newPerson("hahah",8)
	fmt.Println(*p)
}

//用new开头
func newPerson(name string ,age int) *person{

	return &person{
		name: name,
		age: age,
	}
}

方法接收者

方法作用于特定的类型函数,而不是被所有人都能调用

func main() {
	p := newPerson("hahah",8)
	fmt.Println(*p)
	p.Dream()
}

//Dream Person做梦的方法
func (p person) Dream() {
	fmt.Printf("%s的梦想是学好Go语言!\n", p.name)
}

值类型的接收者

这块是不会修改person对象的值的,都是对副本的操作。想要改值要传 *person

func (p person) Dream() {
	p.sex = "18"
}

嵌套结构体

type Person struct {
	name string
	age  int
	Address Address
}

type Address struct {
	city string
	province  string
}

func main() {
	p := Person{
		name: "占山",
		age: 13,
		Address: Address{
			city:  "合肥",
			province: "安徽",
		},
	}
	fmt.Println(p)
}

//结果: {占山 13 {合肥 安徽}}

结构体的“继承”

func main() {
	p:= Person2{
		name: "小花",
		age: 121,
		Animal: Animal{
			name: "旺财",
		},
	}
	fmt.Println(p)
	p.chongwu()

}
func (a *Person2) chongwu(){
	fmt.Printf("我是%s的小狗,我的名字叫%s",a.name,a.Animal.name)
}

//输出结果:
{小花 121 {旺财}}
我是小花的小狗,我的名字叫旺财

结构体与JSON序列化

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。
定义嵌套结构体

type Animal struct {
	Name string
}

type Person2 struct {
	Name string
	Age  int
	Animal Animal
}

使用序列化的包

func main() {
	p:= Person2{
		Name: "小花",
		Age: 121,
		Animal: Animal{
			Name: "旺财",
		},
	}

	json, err := json.Marshal(&p)
	if err !=nil{
		panic("error!!!")
	}
	fmt.Printf(string(json))

}

结果:
{“Name”:“小花”,“Age”:121,“Animal”:{“Name”:“旺财”}}

关于go中序列化之后的json数据为空和json数据的key是大写如何改为小写的问题

假设在上述结构体中,我们给所有的成员变量都是小写开头,只有Animal是大写。那么序列化之后的值就是:
{“”,“Animal”:{}}.
在go语言中小写开头的变量是私有的,大写开头的变量是共有的。把person传入序列化的包中,那么就不是同一个包了,因此访问不到,序列化也就是null。
解决办法:
把变量名改为大写即可。
优化:因为大写不符合书写的规范。因此我们想要拿到属性名是小写的json数据。那么该如何做的?

//在对应的属性名之后加上`json:"字段名"`。这里的字段名就是解析之后的json的key值
type Person2 struct {
	Name string `json:"name"`
	Age  int `json:"age"`
	Animal Animal
}

运行结果:
{“name”:“小花”,“age”:121,“Animal”:{“Name”:“旺财”}}。
so 神奇!

go语言反序列化

调用Unmarshal包,帮我转化为指定的结构体数据。
反序列化需要传入指针
我们先把结构小改一下:

type Person2 struct {
	Name string `json:"name"`
	Age  int `json:"age"`
	Animal []Animal
}

反序列化成指定的结构体:

	str := `{"Name":"小花","Age":121,"Animal":[{"Name":"旺财"},{"Name":"旺财2"}]}`
	c1 := &Person2{}
	err := json.Unmarshal([]byte(str), c1)
	if err != nil {
		fmt.Println("json unmarshal failed!")
		return
	}
	fmt.Printf("%v",*c1)

打印的结果:
{小花 121 [{旺财} {旺财2}]}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值