通过函数后恢复类型信息" interface {}"?

时间:2016-05-28 12:06:07

标签: go

我现在遇到Golang的一个轻微架构问题,导致我复制/粘贴了比我更喜欢的代码。我觉得必须有一个解决方案,所以如果可能的话,请告诉我:

当我通过interface {} - 类型的函数参数传递信息时,我开始收到错误,例如"期望的结构或切片"等等...即使我通过的是以前的结构或切片。我意识到在这个函数中接收到它们之后我可以手动将它们转换为另一种类型,但是在这样的实例中这会变得乏味:

  

本地接口类型* interface {}只能从远程解码   界面类型;收到具体类型

...在这种情况下,接收功能似乎需要进行硬编码才能将所有interface {}项目转换回各自的原始类型才能正常工作,因为接收功能函数需要知道确切的类型才能正确处理项目。

有没有办法动态地将Golang interface {}类型变量重新键入其原始类型?这样的事情,How to I convert reflect.New's return value back to the original type ......也许?

编辑:为了澄清,基本上,我将&out传递给一个函数,当它到达另一个内部函数调用时,它需要是它的原始类型。 / p>

示例代码:

// NOTE: This is sort of pseudo-Golang code, not meant to be compiled or taken too seriously.

func PrepareTwoDifferentThings(keyA string, keyB string) {
    var somethingA TypeA;
    var somethingB TypeB;

    loadFromCache(keyA, &somethingA, nil);
    loadFromCache(keyB, &somethingB, nil);

    fmt.Printf("Somethings: %v, %v", somethingA, somethingB);

}

func loadFromCache(key string, isNew, out interface {}, saveNewData interface {}) {
    if err := cache.load(key, &out); err!=nil { // NOTE: Current issue is that this expects "&out" to be `TypeA`/`TypeB` not "interface {}", but I don't want to copy and paste this whole function's worth of code or whatever.
        panic("oh no!");

    }

    if (saveNewData!=nil) {
        cache.save(key, saveNewData); // This doesn't seem to care if "saveNewData" is "interface {}" when saving, but later cache fetches above using the "load()" method to an "interface {}"-typed `&out` parameter throw an exception that the "interface {}" type on `&out` does not match the original when it was saved here (`TypeA`/`TypeB`).

    }

}

2 个答案:

答案 0 :(得分:3)

要将界面类型更改为正确类型,您可以使用type assertions

package main

import r "reflect"

type A struct {
    Name string
}

func main() {
    // No pointer
    aa := A{"name"}
    var ii interface{} = aa

    bb := ii.(A)
    // main.A

    // Pointer
    a := &A{"name"}
    var i interface{} = a

    b := *i.(*A)
    // main.A

    c := i.(*A)
    // *main.A

    d := r.Indirect(r.ValueOf(i)).Interface().(A)
    // main.A
}

Playground 1

使用类型断言时,您必须知道接口的基础类型。在Go中,无法使用动态类型的类型断言。 reflect.Type不是类型,它是表示类型的接口。所以不,你不能这样使用它。

如果您有多种类型的可能性,解决方案是type switch

package main

import "fmt"

type TypeA struct {
    A string
}

type TypeB struct {
    B string
}

func doSomethingA(t TypeA) {
    fmt.Println(t.A)
}

func doSomethingB(t TypeB) {
    fmt.Println(t.B)
}

func doSomething(t interface{}) {
    switch t := t.(type) {
    case TypeA:
        doSomethingA(t)
    case TypeB:
        doSomethingB(t)
    default:
        panic("Unrecognized type")
    }
}

func main() {
    a := TypeA{"I am A"}
    b := TypeB{"I am B"}

    doSomething(a)
    // I am A
    doSomething(b)
    // I am B
}

Playground 2

答案 1 :(得分:0)

事实证明,使用Gob代替cannot load such file -- bundler/setup (LoadError)进行序列化可以避免我完全遇到的错误。其他函数可以处理传递到接口等。