golang的序列化以及反射

61 阅读7分钟

Json序列化与反序列化

var animla = Animal{
    Name: "ni",
    Age:  3,
    Wife: "sad",
    Hobby: "bash",
}
// Marsha将对象转化为json格字符串,返回byte切片
by, err :=json.Marshal(animla)
if err != nil{
    fmt.Println("转化失败",err)
    return
}
fmt.Println(string(by))
​
// Unmarshal反序列化
var a Animal
s :=`{"name":"ni","age":3,"Hobby":"bash"}`
json.Unmarshal([]byte(s), &a)
fmt.Println(a)
​
 // 序列化和反序列化map
var a map[string]interface{}=make(map[string]interface{})
a["name"] = "小子"
a["age"] = 6
a["address"] = "浦东新区"   
data, _ := json.Marshal(a)
s:=string(data)
fmt.Println(s)
// 反序列化
var m =make(map[string]interface{})
json.Unmarshal([]byte(s),&m)
fmt.Println(m["age"])

xml

// 解析xml
/*
<root version="3">
    <part id = "01" name="选项一">
        <name>我是bili</name>
        <age>今年20岁</age>
        <sex>男</sex>
    </part>
    <part id="02" name="选项二">
        <name>我是李逍遥</name>
        <age>今年22岁</age>
        <sex>男</sex>
    </part>
</root>
-------------------------------
xml中的tag解释:
"-",字段不会输出
"name,attr",以name作为属性名,字段值作为输出这个XML元素的属性
"attr",以这个结构体struct的字段名作为属性名输出XML元素的属性,name默认是字段名
"innerxml",原样输出,不进行常规的编码过程
​
"comment",作为XML注释来输出,不进行编码过程,字段中不能有“--”字符串
"omitempty",若字段值为空、那么字段不会被输出到XML,空值有:false、0、nil指针,nil接口,任意长度为0的Slice、数组结构、Map结构或者string
"chardata",输出XML元素为character data而非element。
*/
// 创建与xml对应的结构体
type Root struct {
    XMLName xml.Name `xml:"root"` // 解析xml标签的名字,类型是xml.Name,对应xml的标签名是root
    Version string `xml:"version,attr"`  // attr是解析标签的属性
    Part []Part `xml:"part"`
}
​
type Part struct {
    Id string `xml:"id,attr"`  // 字段 类型 xmltag
    AName string `xml:"name,attr"`
    Name string `xml:"name"`
    Age string `xml:"age"`
    Sex string `xml:"sex"`
}
​
func main() {
    // 把xml解析到结构体中
    var root Root
    data, err :=ioutil.ReadFile("./text.xml")
    if err != nil{
        fmt.Println("打开文件错误",err)
        return
    }
    err1:=xml.Unmarshal(data,&root)
    if err1 !=nil{
        fmt.Println("解析出错", err1)
    }
    fmt.Println(root)
    for i:=0;i<len(root.Part);i++{
        fmt.Printf("部分编号:%v,部分名:%v,具体姓名:%v,年龄:%v,性别:%v\n",
        root.Part[i].Id,root.Part[i].AName,root.Part[i].Name,root.Part[i].Age,root.Part[i].Sex)
    }
}
​
// 生成xml
func main() {
    var root=Root{Version: "3"}
    // 往root切片中添加Part
    root.Part=append(root.Part, Part{Id: "05", AName: "第二部分", Name: "李华", Age: "18", Sex: "male"})
    root.Part=append(root.Part, Part{Id: "06", AName: "第三部分", Name: "王华", Age: "8", Sex: "male"})
    root.Part=append(root.Part, Part{Id: "07", AName: "第四部分", Name: "吴华", Age: "10", Sex: "female"})
    fmt.Println(root)
​
    // 将结构体转化为xml
    data, err :=xml.Marshal(root)
    if err != nil{
        fmt.Println("xml转化失败")
        return
    }
    werr :=ioutil.WriteFile("./text.xml", data, 0666)
    if werr != nil{
        fmt.Println("文件写入出错", err)
        return
    }
}

MessagePack格式

/*
 MessagePack是一种高效的二进制序列化格式。它允许您像JSON一样在多个语言之间交换数据。但是,它更快并且更小---》可读性差---》不同语言直接数据交互
*/
type Dog struct {
    Name string
    Age int
    Type string  // 狗类型
}
​
// msgpack  序列化
func main() {
    var dog =Dog{"二哈",1,"哈士奇"}
    data,err:=msgpack.Marshal(dog)
    if err != nil {
        fmt.Println("转换出错",err)
        return
    }
    fmt.Println(data)
    fmt.Println(string(data))
    // 存到文件中
    ioutil.WriteFile("./dog.msg",data,0666)
​
    var dog Dog
    // 从文件中读出来
    data,_:=ioutil.ReadFile("./dog.msg")
    msgpack.Unmarshal(data,&dog)
    fmt.Println(dog)
}

Gob格式

//标准库gob是golang提供的“私有”的编解码方式,它的效率会比json,xml等更高,特别适合在Go语言程序间传递数据 相当于是python中的pickle格式
/*
结构体类型使用new创建一个结构体指针没有具体值;结构体直接初始化,创建出一个结构体值;make针对于map,切片类型初始化引用有值是具体值
*/
// 序列化
type Animal struct {
    Name string
    Age int
    Sex string
}
​
func main() {
    var animal=Animal{Name: "鸟",Age: 3, Sex: "male"}
    var buf =new(bytes.Buffer)  // bytes.Buffer实现了io.Writer结构体
    encoder :=gob.NewEncoder(buf)
    err :=encoder.Encode(animal)
    if err != nil{
        fmt.Println("转换出错", err)
        return
    }
    fmt.Println(buf.Bytes())  // bytes.Buffer自带转化为Bytes切片
    // 存入文件
    ioutil.WriteFile("./gob.txt", buf.Bytes(), 0666)
}
​
// 反序列化
file, err :=os.Open("./gob.txt")
if err != nil{
    fmt.Println("文件读取错误",err)
    return
}
var animal Animal
decoder :=gob.NewDecoder(file)
decoder.Decode(&animal)
fmt.Println(animal)

rand标准库

// 生成随机数  "math/rand"生成整形和浮点型和 "crypto/rand"实现了用于加解密的更安全的随机数生成器
// "math/rand"成伪随机数是是否有种子:
    -有种子。通常以时钟、输入输出等特殊节点作为参数,初始化。该类型生成的随机数相比无种子时重复概率较低
    -无种子。可以理解为此时种子为1,无种子编译后运行的结果是定值
​
// 无种子,生成10以内的int值,10以内不包含10
fmt.Println(rand.Intn(10))
​
// 有种子, 设置种子方式一
rand.Seed(time.Now().Unix())
fmt.Println(rand.Intn(100))
// 设置种子方式二
r :=rand.New(rand.NewSource(time.Now().Unix()))
fmt.Println(r.Intn(999))
​
​
// 3 常用方法
/*
    1> 按类型随机类:
    func (r *Rand) Int() int    // 生成一个随机int数字
    func (r *Rand) Int31() int32 // 生成一个int32的数字
    func (r *Rand) Int63() int64 // 生成一个int64的数字
    func (r *Rand) Uint32() uint32 // 生成一个uint32的数字
    func (r *Rand) Float32() float32  // 返回一个取值范围在[0.0, 1.0)的伪随机float32值
    func (r *Rand) Float64() float64  // 返回一个取值范围在[0.0, 1.0)的伪随机float64值
​
    2>指定随机范围类:
    func (r *Rand) Intn(n int) int  // [0,n)
    func (r *Rand) Int31n(n int32) int32
    func (r *Rand) Int63n(n int64) int64
*/
​
//rand.Seed(time.Now().Unix())  // 时间戳
//fmt.Println(rand.Int())
//fmt.Println(rand.Int31())
//fmt.Println(rand.Int63())
//fmt.Println(rand.Uint32())
//fmt.Println(rand.Float32())
//fmt.Println(rand.Float64())
​
// 随机生成100内的整数
//fmt.Println("随机生成100内的整数:",int(rand.Float32()*100))
​
// 使用Intn生成
//fmt.Println(rand.Intn(999))
//fmt.Println(rand.Int31n(100))
//fmt.Println(rand.Int63n(9999))
//fmt.Println("随机生成100内的整数:",rand.Intn(100))
​
// 4 生成定长的随机数   长度是4位的int
//fmt.Println(rand.Int63n(9999))
//res:=rand.Int31()
//fmt.Println(res)
//fmt.Printf("%.4d \n", res%10000)

反射

/*
反射就是在运行时动态的获取一个变量的类型信息和值信息,反射作用是指在程序运行期对程序本身进行访问和修改的能力。程序在编译时,变量被转换为内存地址,变量名不会被编译器写入到可执行部分。在运行程序时,程序无法获取自身的信息。
支持反射的语言可以在程序编译期将变量的反射信息,如字段名称、类型信息、结构体信息等整合到可执行文件中,并给程序提供接口访问反射信息,这样就可以在程序运行期获取类型的反射信息,并且有能力修改它们。
Go程序在运行期使用reflect包访问程序的反射信息
Go语言中的变量是分为两部分的:
    类型信息:预先定义好的元信息。
    值信息:程序运行过程中可动态变化的。
反射的使用
    类型信息:reflect.TypeOf()---》reflect.Type类型
    值信息:reflect.ValueOf()---》reflect.Value类型
反射结构体---》反射结构体字段(根据字符串拿到字段)---》反射结构体方法(根据字符串拿到方法-->调用)
*/
// 1、TypeOf(),ValueOf()
var order1 Order=Order{num: "e3rw", price: 12}
var t reflect.Type=reflect.TypeOf(order1)
var v reflect.Value=reflect.ValueOf(order1)
fmt.Println(t)  // t是一个接口类型
fmt.Println(v)  // v是一个结构体类型// 2、kind()在反射中类型还划分为类型type和种类kind,因为在Go语言中可以使用type关键字构造很多自定义类型,而种类(Kind)就是指底层的类型,但在反射中,当需要区分指针、结构体等大品种的类型时,就会用到种类(Kind)
var order = Order{"1001", 99}
t:=reflect.TypeOf(order)
fmt.Println(t)  // 类型是:main.Order
fmt.Println(t.Kind()) // 种类:struct
var i =9
var s ="lqz"
var sli=make([]int,3)   
var m=make(map[int]string)
fmt.Printf("i的类型是:%s,i的种类是:%s\n",reflect.TypeOf(i),reflect.TypeOf(i).Kind())  // i的类型是:int,i的种类是:int
fmt.Printf("s的类型是:%s,s的种类是:%s\n",reflect.TypeOf(s),reflect.TypeOf(s).Kind())  //s的类型是:string,s的种类是:string
fmt.Printf("sli的类型是:%s,sli的种类是:%s\n",reflect.TypeOf(sli),reflect.TypeOf(sli).Kind())  //sli的类型是:[]int,sli的种类是:slice
fmt.Printf("m的类型是:%s,m的种类是:%s\n",reflect.TypeOf(m),reflect.TypeOf(m).Kind())  // m的类型是:map[int]string,m的种类是:map
/* 所有的种类
Invalid Kind = iota  // 非法类型
Bool                 // 布尔型
Int                  // 有符号整型
Int8                 // 有符号8位整型
Int16                // 有符号16位整型
Int32                // 有符号32位整型
Int64                // 有符号64位整型
Uint                 // 无符号整型
Uint8                // 无符号8位整型
Uint16               // 无符号16位整型
Uint32               // 无符号32位整型
Uint64               // 无符号64位整型
Uintptr              // 指针
Float32              // 单精度浮点数
Float64              // 双精度浮点数
Complex64            // 64位复数类型
Complex128           // 128位复数类型
Array                // 数组
Chan                 // 通道
Func                 // 函数
Interface            // 接口
Map                  // 映射
Ptr                  // 指针
Slice                // 切片
String               // 字符串
Struct               // 结构体
UnsafePointer        // 底层指针
*/
​
// 4 reflect.ValueOf()-->返回的是reflect.Value类型,其中包含了原始值的值信息。reflect.Value与原始值之间可以互相转换
// reflect.Value有一些方法,可以把它转成具体的类型,案例如下
// 整形
var i int =19
v:=reflect.ValueOf(i)
////fmt.Println(v)
res:=v.Int() // res是真正的值,因为v是reflect.Value类型---》res才是int64类型
fmt.Println(res)
​
// 字符串
var s  ="lqz is Nb"
v:=reflect.ValueOf(s)
res:=v.String() // res是真正的值,因为v是reflect.Value类型---》res才是string类型
fmt.Println(res)
​
// 结构体类型
var order = Order{"1001", 99}
v:=reflect.ValueOf(order)
res:=v.Interface()  // 先把结构体转成空接口类型
// 类型断言
o,ok:=res.(Order)
if ok{
    fmt.Println(o) // o才是真正的Order类型
}
​
// 通过反射来获取不同的值:传入不同类型的数据通过判断传入数据的reflect.TypeOf和reflect.ValueOf的kind种类来反射获取此数据对应的值,和此数据的类型
func getRealValue(i interface{})  {
    //1 获得值:reflect.ValueOf()--->reflect.Value类型--》想得到真正的类型
    v:=reflect.ValueOf(i)
    k:=v.Kind()  // 通过判断种类---》强制转换成对应的类型
    switch k {
    case reflect.Int64:
        // 转成具体的值
        // v.Int()从反射中获取整型的原始值,然后通过int64()强制类型转换
        fmt.Printf("该类型是%T类型,值为%d\n", int64(v.Int()),int64(v.Int()))
    case reflect.String:
        fmt.Printf("该类型是%T类型,值为%s\n", v.String(),v.String())
    case reflect.Float32:
        fmt.Printf("该类型是%T类型,值为%f\n", float32(v.Float()),float32(v.Float()))
    case reflect.Float64:
        fmt.Printf("该类型是%T类型,值为%f\n", v.Float(),v.Float())
    case reflect.Struct:
        r:=v.Interface() // 转成空接口类型
        o,ok:=r.(Order)
        if ok {
            fmt.Printf("该类型是%T类型,值为:%v\n",o,o)
        }
    }
}
​
// 通过反射来修改变量,都是通过反射到变量对应的地址然后进行修改,一下示例是修改数字理性和字符串类型,其他类型修改方式类似
i :=10
v :=reflect.ValueOf(&i)
v.Elem().SetInt(99)  // 取到原来的地址然后修改值
fmt.Println(i)
s :="dsf"
v2 :=reflect.ValueOf(&s)
v2.Elem().SetString("fdsdfds")
fmt.Println(s)
​
// reflect.ValueOf的方法isNil()、isValid()
//IsValid()返回v是否持有一个值。如果v是Value零值会返回假,此时v除了IsValid、String、Kind之外的方法都会导致panic。
//IsNil()常被用于判断指针是否为空;IsValid()常被用于判定返回值是否有效
​
// 反射结构体==》反射结构体中所有的字段===》反射结构体字段值以及方法并执行
type Order2 struct {
    orderId string `json:"order_id"` // 通过反射,tag也能拿到
    price   int    `json:"price"`
}
func (o Order2)PrintOrder()  {
    fmt.Printf("订单号为:%s,价格为:%d\n",o.orderId,o.price)
}
func (o Order2)ChangePrice(price int)  {
    o.price=price
    fmt.Println("价格被改为:",o.price)
} 
​
func main() {
    var order Ord = Ord{OrderId: "fdsf",price: 12}
    t :=reflect.TypeOf(order)
    // t.Name 类型
    // t.Kind 种类
    fmt.Println(t.Name(), t.Kind())
    fmt.Println(t.NumField())  // 结构体中有几个字段
​
    // 循环取出所有字段
    for i:=0;i<t.NumField();i++{
        field:=t.Field(i)
        fmt.Printf("name:%s,index:%d,type:%v,json tag%v", field.Name, field.Index, field.Type,                          field.Tag)
    }
​
    // 通过字符串获取字段
    field, ok:=t.FieldByName("price")
    if ok{
        fmt.Printf("name:%s,index:%d,type:%v,json tag%v", field.Name, field.Index, field.Type,                  field.Tag)
    }
    
    // 通过反射结构体方法执行
    var order Order2 = Order2{orderId: "ewqew", price: 223}
    v:=reflect.ValueOf(order)
    t:=reflect.TypeOf(order)
    val :=v.FieldByName("price")
    fmt.Printf("结构体的price的值为%v\n", val)
    // 对象才有方法,使用reflect.ValueOf
    fmt.Println(v.NumMethod())  // 查看对象有多少方法
    for j:=0;j<v.NumMethod();j++{
        methodv:=v.Method(j)
        methodt:=t.Method(j)
        fmt.Printf("方法名叫%s\n",methodt.Name)
        fmt.Printf("方法l类型是%s\n",methodv.Type())
    }
​
    // 通过字符串明获取对象方法并执行
    f :=v.MethodByName("PrintOrder")
    var args1 = []reflect.Value{}
    f.Call(args1)
​
    // 调用有参数的方法
    f2 :=v.MethodByName("ChangePrice")
    var args2 = []reflect.Value{reflect.ValueOf(55)}
    f2.Call(args2)
}
​