• 函数
    • Serialize 函数
    • Unserialize 函数
    • Marshal 函数
    • Unmarshal 函数
    • RegisterSliceEncoder 函数
    • RegisterMapEncoder 函数
    • Register 函数
    • GetStructType 函数
    • GetAlias 函数
    • GetTag 函数

    函数

    Serialize 函数

    1. func Serialize(v interface{}, simple bool) []byte

    v 序列化为字节切片。simple 参数的含义与 Writer 结构体的序列化的 simple 参数相同。

    Unserialize 函数

    1. func Unserialize(b []byte, p interface{}, simple bool)

    将字节切片数据 b 反序列化到 p 所指向的变量中,p 是一个指向反序列化变量的指针。simple 参数的含义与 Reader 结构体的序列化的 simple 参数相同。

    Marshal 函数

    1. func Marshal(v interface{}) []byte

    相当于 Serialize(v, true)

    Unmarshal 函数

    1. func Unmarshal(b []byte, p interface{})

    相当于 Unserialize(b, p, true)

    RegisterSliceEncoder 函数

    1. func RegisterSliceEncoder(s interface{}, encoder func(*Writer, interface{}))

    该函数用于注册一个 slice 编码器实现对 slice 的快速的 hprose 序列化。hprose 对如下 slice 类型已经提供了内置的快速编码器:

    • []bool
    • []int
    • []int8
    • []int16
    • []int32
    • []int64
    • []uint
    • []uint8
    • []uint16
    • []uint32
    • []uint64
    • []uintptr
    • []float32
    • []float64
    • []complex64
    • []complex128
    • []string
    • [][]byte
    • []interface{}
      用户不需要为上述 slice 类型注册自定义编码器。

    对于没有提供快速编码器的类型,hprose 采用反射的方式进行序列化。如果用户想要加快某个复杂的 slice 类型的序列化,可以使用该函数来注册自定义编码器,下面来看一个例子:

    1. package main
    2.  
    3. import (
    4. "fmt"
    5. "time"
    6.  
    7. "github.com/hprose/hprose-golang/io"
    8. "github.com/hprose/hprose-golang/util"
    9. )
    10.  
    11. func mySliceEncoder(w *io.Writer, v interface{}) {
    12. slice := v.([]map[string]interface{})
    13. var buf [20]byte
    14. for i := range slice {
    15. w.WriteByte(io.TagMap)
    16. w.Write(util.GetIntBytes(buf[:], int64(len(slice[i]))))
    17. w.WriteByte(io.TagOpenbrace)
    18. for key, val := range slice[i] {
    19. w.WriteString(key)
    20. w.Serialize(val)
    21. }
    22. w.WriteByte(io.TagClosebrace)
    23. }
    24. }
    25.  
    26. func test(slice []map[string]interface{}) {
    27. start := time.Now()
    28. for i := 0; i < 500000; i++ {
    29. io.Marshal(slice)
    30. }
    31. stop := time.Now()
    32. fmt.Println((stop.UnixNano() - start.UnixNano()) / 1000000)
    33. }
    34.  
    35. func main() {
    36. slice := make([]map[string]interface{}, 10)
    37. for i := 0; i < 10; i++ {
    38. slice[i] = make(map[string]interface{})
    39. slice[i]["id"] = i
    40. }
    41. test(slice)
    42. io.RegisterSliceEncoder(([]map[string]interface{})(nil), mySliceEncoder)
    43. test(slice)
    44. }

    该程序运行结果为:


    1. 844
    2. 664

    我们看到,实现快速编码器之后,效率提高了大约 20% 左右。当然实现快速编码器需要了解 hprose 的编码规范。如果上面的编码器只是实现为:

    1. func mySliceEncoder(w *io.Writer, v interface{}) {
    2. slice := v.([]map[string]interface{})
    3. for i := range slice {
    4. w.Serialize(slice[i])
    5. }
    6. }

    并不会加快序列化速度,反而会比默认方式更慢。所以,在自定义编码器时,最好测试一下注册前后的性能对比。

    RegisterSliceEncoder 函数的第一个参数是编码器所要序列化的数据类型的一个实例。它必须是一个 slice 类型的实例,并且跟后面注册的编码器中所序列化的类型相一致。

    RegisterMapEncoder 函数

    1. func RegisterMapEncoder(m interface{}, encoder func(*Writer, interface{}))

    该函数用于注册一个 map 编码器实现对 map 的快速的 hprose 序列化。hprose 对如下 map 类型已经提供了内置的快速编码器:

    • map[string]string
    • map[string]interface{}
    • map[string]int
    • map[int]int
    • map[int]string
    • map[int]interface{}
    • map[interface{}]interface{}
    • map[interface{}]int
    • map[interface{}]string
      用户不需要为上述 map 类型注册自定义编码器。

    对于没有提供快速编码器的类型,hprose 采用反射的方式进行序列化。如果用户想要加快某个其它 map 类型的序列化,可以使用该函数来注册自定义编码器,下面来看一个例子:

    1. package main
    2.  
    3. import (
    4. "fmt"
    5. "math"
    6. "time"
    7.  
    8. "github.com/hprose/hprose-golang/io"
    9. )
    10.  
    11. func stringFloat64MapEncoder(w *io.Writer, v interface{}) {
    12. m := v.(map[string]float64)
    13. for key, val := range m {
    14. w.WriteString(key)
    15. w.WriteFloat(val, 64)
    16. }
    17. }
    18.  
    19. func test(m map[string]float64) {
    20. start := time.Now()
    21. for i := 0; i < 500000; i++ {
    22. io.Marshal(m)
    23. }
    24. stop := time.Now()
    25. fmt.Println((stop.UnixNano() - start.UnixNano()) / 1000000)
    26. }
    27.  
    28. func main() {
    29. m := make(map[string]float64)
    30. m["e"] = math.E
    31. m["pi"] = math.Pi
    32. m["ln2"] = math.Ln2
    33. test(m)
    34. io.RegisterMapEncoder((map[string]float64)(nil), stringFloat64MapEncoder)
    35. test(m)
    36. }

    该程序运行结果为:


    1. 680
    2. 429

    我们看到,实现快速编码器之后,效率提高了大约 35% 左右。

    RegisterMapEncoder 函数的第一个参数是编码器所要序列化的数据类型的一个实例。它必须是一个 map 类型的实例,并且跟后面注册的编码器中所序列化的类型相一致。

    Register 函数

    1. func Register(proto interface{}, alias string, tag ...string)

    该函数用于注册一个可序列化和反序列化的自定义结构体。

    第一个参数 proto 为注册的结构体对象,它也可以是结构体指针。

    第二个参数 alias 为注册的结构体的别名,该名称可以跟结构体类型名称相同,也可以不同。它用于在不同语言的不同定义之间进行类型映射。

    第三个参数 tag 是可选的(可以是 0 个或 1 个,但不支持多个),它用于指定序列化字段别名的 tag 标签名。

    假设有如下结构体定义:

    1. type User struct {
    2. Name string `json:"name"`
    3. Age int `json:"age"`
    4. Password string `json:"-"`
    5. }

    那么可以这样注册:

    1. func init() {
    2. io.Register((*User)(nil), "User", "json")
    3. }

    注册之后的 User 类型的对象,在序列化时,字段名按照 json 标签对应的名称进行序列化,如果 json 标签对应的名称为 "-",那么该字段将不会被序列化。另外,私有字段也不会被序列化。当没有指定标签时,字段名会自动按照小写首字母的名称进行序列化。

    GetStructType 函数

    1. func GetStructType(alias string) (structType reflect.Type)

    获取用 Register 函数注册的类型。

    GetAlias 函数

    1. func GetAlias(structType reflect.Type) string

    获取用 Register 函数注册的类型对应的别名。

    GetTag 函数

    1. func GetTag(structType reflect.Type) string

    获取用 Register 函数注册的类型对应的标记。