【问题标题】:In go (golang), how can you cast an interface pointer into a struct pointer?在 go (golang) 中,如何将接口指针转换为结构指针?
【发布时间】:2015-03-23 22:47:02
【问题描述】:

我想使用一些需要指向结构的指针的外部代码。在调用代码时,我有一个接口变量。

当从该变量创建指针时,指针的类型是interface{}*,而我需要它是结构类型的指针类型。

TestCanGetStructPointer中的代码进行映像不知道Cat类,并且它存在于某个外部包中。

我怎样才能把它转换成这个?

这是一个代码示例:

import (
    "reflect"
    "testing"
)   

type Cat struct {
    name string
}

type SomethingGeneric struct {
    getSomething func() interface{}
}

func getSomeCat() interface{} {
    return Cat{}
}

var somethingForCats = SomethingGeneric{getSomething: getSomeCat}

func TestCanGetStructPointer(t *testing.T) {
    interfaceVariable := somethingForCats.getSomething()

    pointer := &interfaceVariable

    interfaceVarType := reflect.TypeOf(interfaceVariable)
    structPointerType := reflect.PtrTo(interfaceVarType)
    pointerType := reflect.TypeOf(pointer)

    if pointerType != structPointerType {
        t.Errorf("Pointer type was %v but expected %v", pointerType, structPointerType)
    }

}

测试失败:

Pointer type was *interface {} but expected *parameterized.Cat

【问题讨论】:

  • x := somethingForCats.getSomething().(Cat); &x 除非您将 return Cat{} 更改为 return &Cat{}return new(Cat),然后再更改为 somethingForCats.getSomething().(*Cat)Read the spec on type assertions.
  • @DaveC 嗯,可以玩一点,但绝对不是性能好:stackoverflow.com/a/29222497/1162491
  • @DaveC 运行此代码的位置不会知道 Cat 类型,因此它不能直接转换为该类型。此外,此代码需要适用于任何类型的 getSomething() 返回。它适用于单独包中的代码。您可以将指向接口的指针传递到此外部包中。
  • @OvedD 然后编辑您的问题。目前第一段说你有一个interface{} 并且需要一个*structType 才能通过其他地方。类型断言是最简单的方法。

标签: go


【解决方案1】:

@dyoo 的示例确实有效,但它依赖于您手动转换 DogCat

这是一个有点复杂/冗长的例子,它在一定程度上避免了这种约束:

package main

import (
    "fmt"
    "reflect"
)

type Cat struct {
    name string
}

type SomethingGeneric struct {
    getSomething func() interface{}
}

func getSomeCat() interface{} {
    return Cat{name: "Fuzzy Wuzzy"}
}

var somethingForCats = SomethingGeneric{getSomething: getSomeCat}

func main() {
    interfaceVariable := somethingForCats.getSomething()
    castVar := reflect.ValueOf(interfaceVariable)
    castVar.Convert(castVar.Type())

    // If you want a pointer, do this:
    fmt.Println(reflect.PtrTo(castVar.Type()))

    // The deref'd val
    if castVar.Type() != reflect.TypeOf(Cat{}) {
        fmt.Printf("Type was %v but expected %v\n", castVar, reflect.TypeOf(&Cat{}))
    } else {
        fmt.Println(castVar.Field(0))
    }
}

Playground Link

【讨论】:

    【解决方案2】:

    我找到了这个帖子:https://groups.google.com/forum/#!topic/golang-nuts/KB3_Yj3Ny4c

    package main
    
    import (
        "fmt"
        "reflect"
    )
    
    type Cat struct {
        name string
    }
    
    //
    // Return a pointer to the supplied struct via interface{}
    //
    func to_struct_ptr(obj interface{}) interface{} {
    
        fmt.Println("obj is a", reflect.TypeOf(obj).Name())
    
        // Create a new instance of the underlying type 
        vp := reflect.New(reflect.TypeOf(obj))
    
        // Should be a *Cat and Cat respectively
        fmt.Println("vp is", vp.Type(), " to a ", vp.Elem().Type())
    
        vp.Elem().Set(reflect.ValueOf(obj))
    
        // NOTE: `vp.Elem().Set(reflect.ValueOf(&obj).Elem())` does not work
    
        // Return a `Cat` pointer to obj -- i.e. &obj.(*Cat)
        return vp.Interface()
    }
    
    //
    // Dump out a pointer ...
    //
    func test_ptr(ptr interface{}) {
        v := reflect.ValueOf(ptr)
        fmt.Println("ptr is a", v.Type(), "to a", reflect.Indirect(v).Type())
    }
    
    func main() {
        cat := Cat{name: "Fuzzy Wuzzy"}
    
        // Reports "*main.Cat"
        test_ptr(&cat)
    
        // Get a "*Cat" generically via interface{}
        sp := to_struct_ptr(cat)
    
        // *should* report "*main.Cat" also
        test_ptr(sp)
    
        fmt.Println("sp is",sp)
    }
    

    【讨论】:

      【解决方案3】:

      以下内容可能会有所帮助:http://play.golang.org/p/XkdzeizPpP

      package main
      
      import (
          "fmt"
      )
      
      type Cat struct {
          name string
      }
      
      type Dog struct {
          name string
      }
      
      type SomethingGeneric struct {
          getSomething func() interface{}
      }
      
      func getSomeCat() interface{} {
          return Cat{name: "garfield"}
      }
      
      func getSomeDog() interface{} {
          return Dog{name: "fido"}
      }
      
      var somethings = []SomethingGeneric{
          SomethingGeneric{getSomething: getSomeCat},
          SomethingGeneric{getSomething: getSomeDog},
      }
      
      func main() {
          for _, something := range somethings {
              interfaceVariable := something.getSomething()
      
              cat, isCat := interfaceVariable.(Cat)
              dog, isDog := interfaceVariable.(Dog)
      
              fmt.Printf("cat %v %v\n", cat, isCat)
              fmt.Printf("dog %v %v\n", dog, isDog)
          }
      }
      

      【讨论】:

      • 运行此代码的代码无权访问 Cat 或 Dog 类
      猜你喜欢
      • 2015-01-26
      • 2014-08-16
      • 2015-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多