redis: can‘t unmarshal *[]User (consider implementing BinaryUnmarshaler)

Source

1、问题

通常我们使用go-redis用来Get/Set读取或者存储数据时,使用数据类型为string正常,但是使用对象、数组出现以下错误
redis: can't marshal *main.UserArray (implement encoding.BinaryMarshaler)
redis: can't unmarshal *main.UserArray (consider implementing BinaryUnmarshaler)

2、原因

我跟踪了Scan方法,发现以下标记的地方报错,是由于我们未将类型声明encoding.BinaryMarshaler方法

func Scan(b []byte, v interface{
    
      }) error {
    
      
	switch v := v.(type) {
    
      
	case nil:
		return fmt.Errorf("redis: Scan(nil)")
	case *string:
		*v = util.BytesToString(b)
		return nil
	case *[]byte:
		*v = b
		return nil
	case *int:
		var err error
		*v, err = util.Atoi(b)
		return err
	case *int8:
		n, err := util.ParseInt(b, 10, 8)
		if err != nil {
    
      
			return err
		}
		*v = int8(n)
		return nil
	case *int16:
		n, err := util.ParseInt(b, 10, 16)
		if err != nil {
    
      
			return err
		}
		*v = int16(n)
		return nil
	case *int32:
		n, err := util.ParseInt(b, 10, 32)
		if err != nil {
    
      
			return err
		}
		*v = int32(n)
		return nil
	case *int64:
		n, err := util.ParseInt(b, 10, 64)
		if err != nil {
    
      
			return err
		}
		*v = n
		return nil
	case *uint:
		n, err := util.ParseUint(b, 10, 64)
		if err != nil {
    
      
			return err
		}
		*v = uint(n)
		return nil
	case *uint8:
		n, err := util.ParseUint(b, 10, 8)
		if err != nil {
    
      
			return err
		}
		*v = uint8(n)
		return nil
	case *uint16:
		n, err := util.ParseUint(b, 10, 16)
		if err != nil {
    
      
			return err
		}
		*v = uint16(n)
		return nil
	case *uint32:
		n, err := util.ParseUint(b, 10, 32)
		if err != nil {
    
      
			return err
		}
		*v = uint32(n)
		return nil
	case *uint64:
		n, err := util.ParseUint(b, 10, 64)
		if err != nil {
    
      
			return err
		}
		*v = n
		return nil
	case *float32:
		n, err := util.ParseFloat(b, 32)
		if err != nil {
    
      
			return err
		}
		*v = float32(n)
		return err
	case *float64:
		var err error
		*v, err = util.ParseFloat(b, 64)
		return err
	case *bool:
		*v = len(b) == 1 && b[0] == '1'
		return nil
	case *time.Time:
		var err error
		*v, err = time.Parse(time.RFC3339Nano, util.BytesToString(b))
		return err
	case *time.Duration:
		n, err := util.ParseInt(b, 10, 64)
		if err != nil {
    
      
			return err
		}
		*v = time.Duration(n)
		return nil
	case encoding.BinaryUnmarshaler:
		return v.UnmarshalBinary(b)
	default:
		//在这里报错了
		return fmt.Errorf(
			"redis: can't unmarshal %T (consider implementing BinaryUnmarshaler)", v)
	}
}

3、解决方法(对象)

package main

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/go-redis/redis/v8"
)

type User struct {
    
      
	UserId   string `json:"user_id"`
	UserName string `json:"user_name"`
}

//序列化
func (m *User) MarshalBinary() (data []byte, err error) {
    
      
	fmt.Println("MarshalBinary")
	return json.Marshal(m)
}

//反序列化
func (m *User) UnmarshalBinary(data []byte) error {
    
      
	fmt.Println("UnmarshalBinary")
	return json.Unmarshal(data, m)

}

func main() {
    
      
	var ctx = context.Background()
	redis := redis.NewClient(&redis.Options{
    
      
		Addr:     "127.0.0.1:6379",
		Password: "",
		DB:       0,
	})
	user := User{
    
      
		UserId:   "123",
		UserName: "name",
	}
	fmt.Println("设置缓存")
	err := redis.Set(ctx, "user_key", &user, 0).Err()
	if err != nil {
    
      
		fmt.Println(err)
	}

	result := User{
    
      }
	fmt.Println("读取缓存")
	err = redis.Get(ctx, "user_key").Scan(&result)
	if err != nil {
    
      
		fmt.Println(err)
	}
	fmt.Println("user对象:", result)
}

4、解决方法(数组)

package main

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/go-redis/redis/v8"
)

type User struct {
    
      
	UserId   string `json:"user_id"`
	UserName string `json:"user_name"`
}
type UserArray []User

//序列化
func (m *UserArray) MarshalBinary() (data []byte, err error) {
    
      
	fmt.Println("MarshalBinary")
	return json.Marshal(m)
}

//反序列化
func (m *UserArray) UnmarshalBinary(data []byte) error {
    
      
	fmt.Println("UnmarshalBinary")
	return json.Unmarshal(data, m)

}

func main() {
    
      
	var ctx = context.Background()
	redis := redis.NewClient(&redis.Options{
    
      
		Addr:     "127.0.0.1:6379",
		Password: "",
		DB:       0,
	})
	userArr := UserArray{
    
      }
	user := User{
    
      
		UserId:   "123",
		UserName: "name",
	}
	userArr = append(userArr, user)
	fmt.Println("设置缓存")
	err := redis.Set(ctx, "user_key", &userArr, 0).Err()
	if err != nil {
    
      
		fmt.Println(err)
	}

	result := UserArray{
    
      }
	fmt.Println("读取缓存")
	err = redis.Get(ctx, "user_key").Scan(&result)
	if err != nil {
    
      
		fmt.Println(err)
	}
	fmt.Println("user数组:", result)
}