redigo和gob如何检索gob数据的切片

huangapple go评论84阅读模式
英文:

redigo and gob how to retrieve slices of gob data

问题

我正在使用"RPUSH"命令将对象推送到我的Redis数据库中。

// object 是一个接口类型
var network bytes.Buffer
gob.NewEncoder(&network).Encode(object /* interface{} */)
redis.String(d.Conn.Do("RPUSH", "objects", network.String()))

Redigo按照我的期望工作,它将所有数据结构进行了Gob编码并推送到了Redis中。

现在我正在尝试检索它们:

sall, _ := redis.Strings(d.Conn.Do("LRANGE", "todos", "0", "-1"))
fmt.Printf("%T", sall) // 期望的类型是 []string

// 在这一点上,我不知道是否应该将数据存储在缓冲区中,还是直接转换为字节。实际上,我在这里迷失了
var network bytes.Buffer
var object []interface{}

dec := gob.NewDecoder(&network)
err := dec.Decode(&object)
fmt.Printf("%v", err) // 解码错误:EOF

最好的方法是如何解码它们?我希望将它们作为interface{}的切片返回。但即使我的对象被编码为Gob数据,它们也是按照Redis的方式推送的,所以从Gob的角度来看,它们可以被视为切片吗?

我可以迭代列表并逐个解码它们。但是我对效率不太有信心。我假设Gob希望一个按照它的方式编码的切片结构。所以我的问题是:是否有一种技巧可以高效地将我的Gob数据切片解码为数据结构的集合?或者我应该以另一种方式存储我的数据结构(我假设使用RPUSH存储我的数据可以防止非原子操作)?

英文:

I'm pushing in my redis base my objects with the "RPUSH" command.

// object is of type interface

var network bytes.Buffer
gob.NewEncoder(&network)
enc.Encode(object /* interface{} */)
  
redis.String(d.Conn.Do("RPUSH", "objects", network.String()))

Redigo do what i'm expecting, it is pushing all the data structure gob-encoded.

Now I'm trying to retreive them:

sall, _ := redis.Strings(d.Conn.Do("LRANGE", "todos", "0", "-1"))
fmt.Printf("%T", sall) // type []string as expected

// At this point, I have no idea if I should store the data in a buffer, or convert it directly as bytes. actually, here I'm lost
var network bytes.Buffer
var object []interface{}


dec := gob.NewDecoder(network)
err := dec.Decode(inout)
fmt.Printf("%v", err) // decode error:EOF

What is the best way to gob-decod them? I'd want to get them back as a slice of interface{}. But even if my object are encoded as gob data. They are pushed in the redis way, so can it be considered as a slice from the point view of gob?

I could iterate other the list and decode them one by one. But I'm not confident about the efficiency. I'm assuming gob want a slice structure encoded in its way. So my question is: Is there a trick in order to decode my slice of gob data efficiently as a collection of data structure? Or should I store my data structure in another way (I'm assuming storing my data with RPUSH can prevent non-attomic manipulation)

答案1

得分: 3

LRANGE命令返回一个列表。使用redis.ByteSlices将该列表作为[][]byte获取。解码列表中的每个gob:

items, err := redis.ByteSlices(d.Conn.Do("LRANGE", "objects", "0", "-1"))
if err != nil {
   // 处理错误
}
var values []*Object
for _, item := range items {
    var v Object
    if err := gob.NewDecoder(bytes.NewReader(item)).Decode(&v); err != nil {
        // 处理错误
    }
    values = append(values, &v)
}

这假设为列表中推入的每个值创建了一个新的gob.Encoder。

如果应用程序在Redis中不独立访问列表项,则将整个列表进行gob编码,并将其存储为批量字符串:

var values []*Object
var buf bytes.Buffer
if err := gob.NewEncoder(&buf).Encode(values); err != nil {
    // 处理错误
}
if _, err := d.Conn.Do("SET", "objects", buf.Bytes()); err != nil {
    // 处理错误
}

以下是如何解码它的方法:

items, err := redis.Bytes(d.Conn.Do("GET", "objects"))
if err != nil {
    // 处理错误
}
var values []*Objects
if err := gob.NewDecoder(items).Decode(&values); err != nil {
    // 处理错误
}

关于问题中的这行代码的说明:

redis.String(d.Conn.Do("RPUSH", "objects", network.String()))

使用network.Bytes()来避免字符串分配。使用redis.Int来解码RPUSH的整数返回值。将代码编写为:

n, err := redis.Int(d.Conn.Do("RPUSH", "objects", network.Bytes()))

或者如果你不关心从列表返回的元素数量,可以将其写为:

_, err := d.Conn.Do("RPUSH", "objects", network.Bytes())
英文:

The LRANGE command returns a list. Use redis.ByteSlices to get that list as a [][]byte. Decode each gob in the list:

items, err := redis.ByteSlices(d.Conn.Do("LRANGE", "objects", "0", "-1"))
if err != nil {
   // handle error
}
var values []*Object
for _, item := range items {
    var v Object
    if err := gob.NewDecoder(bytes.NewReader(item)).Decode(&v); err != nil {
        // handle error
    }
    values = append(values, &v)
}

This assumes that a new gob.Encoder was created for each value pushed into the list.

If the application does not access the list items independently in Redis, then gob encode the entire list and store it as a bulk string:

 var values []*Object
 var buf bytes.Buffer
 if err := gob.NewEncoder(&buf).Encode(values); err != nil {
     // handle error
 }
 if _, err := d.Conn.Do("SET", "objects", buf.Bytes()); err != nil {
     // handler error
 }

Here's how to decode it:

items, err := redis.Bytes(d.Conn.Do("GET", "objects"))
if err != nil {
    // handle error
}
var values []*Objects
if err := gob.NewDecoder(items).Decode(&values); err != nil {
    // handle error
}

Here's an aside on this line of code from the question:

 redis.String(d.Conn.Do("RPUSH", "objects", network.String()))

Use network.Bytes() to avoid the string allocation. Use redis.Int to decode the integer return value from RPUSH. Write the code as:

 n, err := redis.Int(d.Conn.Do("RPUSH", "objects", network.Bytes()))

or if you don't care about the count of elements returned from the list, write it as:

 _, err := d.Conn.Do("RPUSH", "objects", network.Bytes())

huangapple
  • 本文由 发表于 2016年8月20日 16:39:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/39052200.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定