传递接口指针和赋值

时间:2014-07-01 16:27:06

标签: go

我想在Go中编写一个文件缓存。我正在使用gob编码,并保存到文件,但我的get函数有一些问题:

package main

import (
    "encoding/gob"
    "fmt"
    "os"
)

var (
    file = "tmp.txt"
)

type Data struct {
    Expire int64
    D      interface{}
}

type User struct {
    Id   int
    Name string
}

func main() {
    user := User{
        Id:   1,
        Name: "lei",
    }
    err := set(file, user, 10)
    if err != nil {
        fmt.Println(err)
        return
    }

    user = User{}
    err = get(file, &user)
    if err != nil {
        fmt.Println(err)
        return
    }

    //user not change.
    fmt.Println(user)

}

func set(file string, v interface{}, expire int64) error {
    f, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
    if err != nil {
        return err
    }
    defer f.Close()

    //wrapper data
    //save v in data.D
    data := Data{
        Expire: expire,
        D:      v,
    }
    gob.Register(v)
    enc := gob.NewEncoder(f)
    err = enc.Encode(data)
    if err != nil {
        return err
    }
    return nil
}

func get(file string, v interface{}) error {
    f, err := os.OpenFile(file, os.O_RDONLY, 0600)
    if err != nil {
        return err
    }
    defer f.Close()

    var data Data
    dec := gob.NewDecoder(f)
    err = dec.Decode(&data)
    if err != nil {
        return err
    }

    //get v
    v = data.D
    fmt.Println(v)

    return nil
}

get函数传递接口类型,我想更改值,但不更改。 http://play.golang.org/p/wV7rBH028o

2 个答案:

答案 0 :(得分:2)

为了将未知值插入v类型的interface{},您需要使用反射。这有点牵扯,但是如果你想完全支持它,你可以通过在一些编码包(jsongob)中完成解码过程来看看它是如何完成的。

为了帮助您入门,以下是使用反射功能的get功能的基本版本。这会跳过许多检查,并且只会解码被编码为指针的内容。

func get(file string, v interface{}) error {
    f, err := os.OpenFile(file, os.O_RDONLY, 0600)
    if err != nil {
        return err
    }
    defer f.Close()

    rv := reflect.ValueOf(v)
    if rv.Kind() != reflect.Ptr || rv.IsNil() {
        panic("need a non nil pointer")
    }

    var data Data
    dec := gob.NewDecoder(f)
    err = dec.Decode(&data)
    if err != nil {
        return err
    }

    dv := reflect.ValueOf(data.D)
    if dv.Kind() != reflect.Ptr {
        panic("didn't decode a pointer")
    }

    rv.Elem().Set(dv.Elem())
    return nil
}

我实际上建议在您自己的代码中使用更简单的方法处理此问题,即让Get函数返回interface{}。由于您将知道此时可能的类型,您可以使用类型开关来断言正确的值。

答案 1 :(得分:1)

另一种方法是直接返回文件中的值:

func get(file string) (interface{}, error) {
    f, err := os.OpenFile(file, os.O_RDONLY, 0600)
    if err != nil {
        return nil, err
    }
    defer f.Close()

    var data Data

    dec := gob.NewDecoder(f)
    err = dec.Decode(&data)
    if err != nil {
        return nil,err
    }

    fmt.Println(data.D)

    return data.D,nil
}

完整的工作示例:http://play.golang.org/p/178U_LVC5y