golang反射自定义tag

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang反射自定义tag相关的知识,希望对你有一定的参考价值。

参考技术A 维基百科中反射的定义:在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。

golang reflect包实现了反射。动态的获得程序运行时对象的结构和信息。

reflect 包中提供了两个基础的关于反射的函数来获取上述的接口和结构体:

func TypeOf(i interface) Type

func ValueOf(i interface) Value

大体上可以这样理解,TypeOf获取对象的类型信息,ValueOf获取对象中存储的值。

golang tag

golang中可以为结构体的字段添加tag。golang本身的encoding/json包解析json使用了tag,一些开源的orm框架如gorm,也使用了tag。tag可以方便的为结构体的字段添加一些信息,用reflect可以读取到,加以利用。

这是一个用tag标记列名以实现结构体自动生成xlsx的例子:

```

type Employee struct

ID int `xlsx:”工号”`

Name string `xlsx:”姓名”`

Email string `xlsx:”邮箱”`



func Outputxlsx(es []*Employee) ([]byte, error)

xt := reflect.TypeOf(es[0])

xv := reflect.ValueOf(es[0])

rows := [][]interface

headers := []interface

for i := 0; i < xt.Elem().NumField(); i++

head, ok := xt.Elem().Field(i).Tag.Lookup("xlsx")

if ok

headers = append(headers, head)





for _, e := range es

cells := []interface

xv := reflect.ValueOf(e)

for i := 0; i < xv.Elem().NumField(); i++

_, ok := xt.Elem().Field(i).Tag.Lookup("xlsx")

if ok

cells = append(cells, xv.Elem().Field(i).Interface())





rows = append(rows, cells)



file := xlsx.NewFile()

sheet, _ := file.AddSheet("sheet1")

row := sheet.AddRow()

for _, header := range headers

row.AddCell().Value = fmt.Sprintf("%v", header)



for _, v := range rows

row := sheet.AddRow()

for _, vv := range v

row.AddCell().Value = fmt.Sprintf("%v", vv)





var buffer bytes.Buffer

if err := file.Write(&buffer); err != nil

return nil, err



return buffer.Bytes(), nil



```

golang 自定义封包协议(转的)

package protocol
 
import (
    "bytes"
    "encoding/binary"
)
 
const (
    ConstHeader         = "jackluo"
    ConstHeaderLength   = 7
    ConstSaveDataLength = 4
)
 
//封包
func Packet(message []byte) []byte {
    return append(append([]byte(ConstHeader), IntToBytes(len(message))...), message...)
}
 
//解包
func Unpack(buffer []byte, readerChannel chan []byte) []byte {
    length := len(buffer)
 
    var i int
    for i = 0; i < length; i = i + 1 {
        if length < i+ConstHeaderLength+ConstSaveDataLength {
            break
        }
        if string(buffer[i:i+ConstHeaderLength]) == ConstHeader {
            messageLength := BytesToInt(buffer[i+ConstHeaderLength : i+ConstHeaderLength+ConstSaveDataLength])
            if length < i+ConstHeaderLength+ConstSaveDataLength+messageLength {
                break
            }
            data := buffer[i+ConstHeaderLength+ConstSaveDataLength : i+ConstHeaderLength+ConstSaveDataLength+messageLength]
            readerChannel <- data
 
            i += ConstHeaderLength + ConstSaveDataLength + messageLength - 1
        }
    }
 
    if i == length {
        return make([]byte, 0)
    }
    return buffer[i:]
}
 
//整形转换成字节
func IntToBytes(n int) []byte {
    x := int32(n)
 
    bytesBuffer := bytes.NewBuffer([]byte{})
    binary.Write(bytesBuffer, binary.BigEndian, x)
    return bytesBuffer.Bytes()
}
 
//字节转换成整形
func BytesToInt(b []byte) int {
    bytesBuffer := bytes.NewBuffer(b)
 
    var x int32
    binary.Read(bytesBuffer, binary.BigEndian, &x)
 
    return int(x)
}
package main

import (
    "fmt"
    "net"
    "os"
    "./protocol"
)

func main() {
    netListen, err := net.Listen("tcp", ":9988")
    CheckError(err)
 
    defer netListen.Close()
 
    Log("Waiting for clients")
    for {
        conn, err := netListen.Accept()
        if err != nil {
            continue
        }
 
        Log(conn.RemoteAddr().String(), " tcp connect success")
        go handleConnection(conn)
    }
}

func handleConnection(conn net.Conn) {
   
    //声明一个临时缓冲区,用来存储被截断的数据
    tmpBuffer := make([]byte, 0) 
    //声明一个管道用于接收解包的数据
    readerChannel := make(chan []byte, 16)
    go reader(readerChannel)

    buffer := make([]byte, 1024)
    for {
        n, err := conn.Read(buffer)
        if err != nil {
            Log(conn.RemoteAddr().String(), " connection error: ", err)
            return
        }
/*        Log(conn.RemoteAddr().String(), "receive data length:", n)
        Log(conn.RemoteAddr().String(), "receive data:", buffer[:n])
        Log(conn.RemoteAddr().String(), "receive data string:", string(buffer[:n]))
*/  
     tmpBuffer = protocol.Unpack(append(tmpBuffer, buffer[:n]...), readerChannel)  
    }
}
func reader(readerChannel chan []byte) {
    for {
        select {
        case data := <-readerChannel:
            Log(string(data))
        }
    }
}
func Log(v ...interface{}) {
    fmt.Println(v...)
}
 
func CheckError(err error) {
    if err != nil {
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
        os.Exit(1)
    }
}
package main
 
import (
    "fmt"
    "net"
    "os"
    "time"
    "./protocol"
)
 
func sender(conn net.Conn) {
    for i := 0; i < 100; i++ {
        words := "{\"Id\":1,\"Name\":\"golang\",\"Message\":\"message\"}"
        conn.Write(protocol.Packet([]byte(words)))
    }
     fmt.Println("send over")
}
 
func main() {
    server := "127.0.0.1:9988"
    tcpAddr, err := net.ResolveTCPAddr("tcp4", server)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
        os.Exit(1)
    }
 
    conn, err := net.DialTCP("tcp", nil, tcpAddr)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
        os.Exit(1)
    }
 
    defer conn.Close()
 
    fmt.Println("connect success")
 
    go sender(conn)
 
    for {
        time.Sleep(1 * 1e9)
    }
}

 

以上是关于golang反射自定义tag的主要内容,如果未能解决你的问题,请参考以下文章

Java自定义注解+反射实现字典码值转换

C#反射与自定义属性

Unity Shaders学习笔记之为创建自定义慢反射光照模型

java自定义类加载器

Golang-ReverseProxy源码分析

如何在golang使用自定义的包