22、做中学 | 高一下期 | Golang反射

学习反射之前,先了解一下JSON

一、什么是JSON

1. 概述

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。key-val

JSON是在2001年开始推广使用的数据格式,目前已经成为主流的数据格式

JSON易于机器解析和生成,并有效地提升网络传输效率,通常程序在网络传输时会先将数据(结构体、map等)序列化成ison字符串,到接收方得到ison字符串时,在反序列化恢复成原来的数据类型(结构体、map等)。这种方式已然成为各个语言的标准。

2. 使用场景

比如:我们后端发送的数据,会序列化为json字符串到前端,那么前端怎么处理呢?

前端拿到json字符串,会进行反序列化json字符串为相应的数据!

3. json格式

在IS语言中,一切都是对象。因此,任何的数据类型都可以通过JSON来表示,例如字符串、数字、对象、数组,map,结构体等.

JSON 键值对是用来保存 数据一种方式,键/值对组合中的键名写在前面并用双引号""包裹,使用冒号:分隔,然后紧接着值:

go 复制代码
// 对象json格式
{"key1":"val1","key2":"val2"}

// 数组对象json格式
[{"key1":"val1","key2":"val2"},{"key1":"val1","key2":"val2"}]

二、JSON序列化

1. json序列化

json序列化是指,将有 key-value 结构的数据类型(比如结构体、map、切片)序列化成json 字符串的操作。

go 复制代码
func TestJson(t *testing.T) {
	p := Person{"Bob", 20}
	marshal, _ := json.Marshal(p)
	fmt.Println(string(marshal))
}
//=== RUN   TestJson
//{"Name":"Bob","Age":20}
//--- PASS: TestJson (0.00s)
//PASS

2. json反序列化

实现了Unmarshaler接口的对象可以将自身的json描述反序列化。该方法可以认为输入是合法的json字符串。如果要在方法返回后保存自身的json数据,必须进行拷贝。

go 复制代码
type Unmarshaler interface {
    UnmarshalJSON([]byte) error
}

测试下反序列化

go 复制代码
func TestUnmarshal(t *testing.T) {
	jsonStr := `{"Name":"Bob","Age":20}`
	p := Person{}
	err := json.Unmarshal([]byte(jsonStr), &p)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Printf("Person=%v,Person.Name=%v\n", p, p.Name)
}

//=== RUN   TestUnmarshal
//Person={Bob 20},Person.Name=Bob
//--- PASS: TestJson2 (0.00s)
//PASS

3. json属性标签

go语言的属性是通过首字母大小写,进行控制权限的,如何进行格式化变为小写,可以使用属性标签的写法,其实就是别名的意思。

go 复制代码
type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age,string"`
}

func TestJsonTag(t *testing.T) {
	p := Person{"Bob", 20}
	marshal, _ := json.Marshal(p)
	fmt.Println(string(marshal))
}
//=== RUN   TestJsonTag
//{"name":"Bob","age":"20"}
//--- PASS: TestJsonTag (0.00s)
//PASS

属性名称和类型进行了重新定义

三、反射

1. 反射基本介绍

  1. 反射可以在运行时动态获取变量的各种信息,比如变量的类型(type),类别(kind)
  2. 如果是结构体变量,还可以获取到结构体本身的信息(包括结构体的字段、方法)
  3. 通过反射,可以修改变量的值,可以调用关联的方法。
  4. 使用反射,需要 import("reflect")

2. 反射应用场景

1.不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这种需要对函数或方法反射。

go 复制代码
func bridge(funPtr interface{}, args ..interface{})

第一个参数funcPtr以接口的形式传入函数指针,函数参数args以可变参数的形式传入,bridge函数中可以用反射来动态执行funcPtr函数

2.对结构体序列化时,如果结构体有指定Tag,也会使用到反射生成对应的字符串。

go 复制代码
type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age,string"`
}

func TestJsonTag(t *testing.T) {
	p := Person{"Bob", 20}
	marshal, _ := json.Marshal(p)
	fmt.Println(string(marshal))
}

3. 使用到的函数

  1. reflect.TypeOf(变量名): 获取变量的类型,返回reflect.Type类型
  2. reflect.ValueOf(变量名): 获取变量的值,返回reflect.Value类型reflect.Value 是一个结构体类型。
  3. 变量、interface[]和reflect.Value是可以相互转换的,这点在实际开发中,会经常使用到。

4. 简单示例

1.通过反射获取变量的类型和值

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

func reflectTest01(b interface{}) {

	// 获取变量的 reflect.Type
	numType := reflect.TypeOf(b)
	fmt.Println(numType)
	// int

	// 获取变量的 reflect.Value
	numValue := reflect.ValueOf(b)
	fmt.Println(numValue)
	// 10

	// 获取的变量值转换未interface{}
	numInter := numValue.Interface()

	// 将interface{}转换成具体类型
	numInterType := numInter.(int)
	fmt.Println(numInterType)
	// 10
}

func main() {
	var num int = 10
	reflectTest01(num)
}

2.通过反射获取结构体类型和值

go 复制代码
package main

import (
	"fmt"
	"reflect"
)

func reflectTest02(b interface{}) {

	// 获取变量的 reflect.Type
	monsterType := reflect.TypeOf(b)
	fmt.Println(monsterType)
	// main.Monster

	// 获取变量的 reflect.Value
	monsterValue := reflect.ValueOf(b)
	fmt.Println(monsterValue)
	// {xiaoming 10}

	// 获取的变量值转换未interface{}
	monsterInter := monsterValue.Interface()

	// 将interface{}转换成具体类型
	studentInterType := monsterInter.(Monster)
	fmt.Println(studentInterType)
	// {xiaoming 10}
}

type Monster struct {
	Name string
	Age  int
}

func main() {
	Monster := Monster{
		Name: "xiaoming",
		Age:  10,
	}
	reflectTest02(Monster)
}

本篇简单介绍了反射使用到的json格式,并介绍了反射使用到的方法

通过TypeOf获取变量和结构体的类型,通过ValueOf获取变量和结构体的值

本篇过于简单,说明了反射基本概念和简单入门,相关文档

goAPI文档:https://studygolang.com/pkgdoc

reflect包文档:https://studygolang.com/static/pkgdoc/pkg/reflect.htm

相关推荐
小陈phd2 小时前
langGraph从入门到精通(四)——基于LangGraph的State状态模式设计
python·microsoft·状态模式
a努力。2 小时前
中国电网Java面试被问:Dubbo的服务目录和路由链实现
java·开发语言·jvm·后端·面试·职场和发展·dubbo
itwangyang5202 小时前
人工智能药物设计和生信常用 R 包一键全自动安装脚本
开发语言·人工智能·r语言
catchadmin2 小时前
PHP 8.5 升级生存指南:避免凌晨两点回滚的检查清单
开发语言·php
3824278272 小时前
JS正则表达式实战:核心语法解析
开发语言·前端·javascript·python·html
zh_xuan2 小时前
kotlin伴生对象
开发语言·kotlin
你怎么知道我是队长2 小时前
C语言---递归
c语言·开发语言
superman超哥2 小时前
实时互动的基石:Rust WebSocket 实现的架构之美
开发语言·rust·编程语言·rust websocket·rust实施互通·rust架构之美
古城小栈2 小时前
编译型 VS 解释型, 快慢有道
开发语言