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的主要内容,如果未能解决你的问题,请参考以下文章