我现在在使用 Golang 时遇到了一个轻微的架构问题,这导致我复制/粘贴的代码比我喜欢的要多一些。我觉得必须有一个解决方案,所以请让我知道这是否可能:
当我通过一个interface {}-typed 函数参数传递东西时,我开始收到诸如“预期的结构或切片”之类的错误……即使我以前传递的是一个结构或切片。我意识到我可以在该函数中接收它们后手动将它们转换为另一种类型,但是在这样的情况下这变得乏味:
本地接口类型 *interface {} 只能从远程接口类型解码;收到的具体类型
...在这种情况下,接收函数似乎需要进行硬编码才能转换所有 interface {}项目回其各自的原始类型才能正常工作,因为接收函数需要知道确切的类型才能正确处理该项目。
有没有办法动态地将 Golanginterface {}类型变量重新键入回它们的原始类型?像这样的东西,如何将reflect.New的返回值转换回原始类型......也许?
编辑:为了澄清,基本上,我传递&out给一个函数,它需要在到达另一个内部函数调用时成为其原始类型。
示例代码:
// 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`).
}
}
Run Code Online (Sandbox Code Playgroud)
要将接口的类型更改为正确的类型,您可以使用类型断言:
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
}
Run Code Online (Sandbox Code Playgroud)
使用类型断言时,您必须知道接口的基础类型。在 Go 中,无法对动态类型使用类型断言。reflect.Type不是类型,它是表示类型的接口。所以不,你不能这样使用它。
如果您有多种类型的可能性,则解决方案是类型开关:
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
}
Run Code Online (Sandbox Code Playgroud)