Go中接口类型的间接

时间:2018-06-26 15:15:43

标签: pointers go

我正在尝试创建一个函数,该函数将创建接口的新实例,并将该实例分配给具有接口类型的变量。这是一个简单的示例程序(无法编译):

package main

import (
    "fmt"
)

type Foo interface {
    Foo(int) int
}

type Foo_impl struct {}

func (f *Foo_impl) Foo(x int) int {
    return x * 2
}

func main() {
    var x *Foo_impl
    constructFoo(x)

    fmt.Println("Hello, playground")
}

func constructFoo(x Foo) {
    *x = Foo_impl{} // Blows up here - invalid indirect of x (type Foo)
}

是否可以通过反射来间接调用接口变量并分配给基础值?如果我不使用接口,我会做这样的事情,

func main() {
    var x int
    foo(&x)
    fmt.Printf("%d\n", x)
}

func foo(x *int) {
    *x = 4
}

并且如预期的那样,它将打印出4。问题是接口变量不能以常规方式间接进行。有办法解决吗?

6 个答案:

答案 0 :(得分:3)

但是你为什么不能变得更加惯用而做

func constructFoo() Foo {
    return &Foo_impl{} 
}

然后,主要是:

func main() {
    fmt.Println(constructFoo().Foo(10))
}

此外,还有一种accept interfaces, return structs方法可能对您来说很有趣。

希望这会有所帮助。

答案 1 :(得分:1)

我能够编写出满足我要求的功能

df

package main import ( "fmt" "reflect" ) type Y interface { SetX(int) } type X struct { test int } func (x *X) SetX(param int) { x.test = param } func main() { var x *X y := foo(&x) y.SetX(12) fmt.Printf("%+v", x) } func foo(x interface{}) Y { t := reflect.TypeOf(x) pointerType := t.Elem() realType := pointerType.Elem() pointer := reflect.New(realType) reflect.Indirect(reflect.ValueOf(x)).Set(pointer) return pointer.Interface().(Y) } 函数可以初始化任何指向实现foo的类型的双指针,并将新实例作为Y返回。

答案 2 :(得分:0)

在Go中,如果我们有类型

type Foo_impl struct {}

我们通常使用

func NewFoo_impl() *Foo_impl

创建此结构的此实例(如果需要)

没有接口实例,我们只是说一个类型是否实现一个接口。

因此您的代码可以

var x Foo
x = NewFoo_impl()
// or x = &Foo_impl{}

关于间接接口类型,不难理解,就像C语言中的void*一样。

取消引用它不会返回您想要的类型,实际上,编译器也不知道如何处理它。它变成了不完整的类型,因此Go的决定不允许这样做。

答案 3 :(得分:0)

实现接口将帮助您将模拟结构传递给函数,然后使用类型断言获得结构的值。基本上,接口是包装任何类型并将其传递给函数然后使用类型断言可以获取基础值的唯一方法。

package main

import (
        "fmt"
)

type Foo interface {
    Foo(int) int
}

type Foo_impl struct {}

func (f *Foo_impl) Foo(x int) int {
    return x * 2
}

func main() {
    var x *Foo_impl
    constructFoo(x)
}

func constructFoo(x interface{}) {
    fmt.Println(x.(interface{}).(*Foo_impl).Foo(10)) // dereference the type to call the function  on pointer receiver
}

还需要取消引用传递给构造函数的struct类型的值,以使用指针接收器调用该方法。

检查Go Playground上的工作代码

在Golang Type assertions中定义为:

  

对于接口类型为T且类型为T的表达式x,主要   表达

x.(T)
     

断言x不是nil,并且存储在x中的值是T类型。   x。(T)称为类型断言。

     

更准确地说,如果T不是接口类型,则x。(T)断言   x的动态类型与T相同。在这种情况下,T必须   实现x的(接口)类型;否则类型断言是   无效,因为x不可能存储类型T的值。   T是接口类型,x。(T)断言x的动态类型   实现接口T。

答案 4 :(得分:0)

这是满足您要求的解决方案,但是传递给构造函数方法的类型的指针不能为nil,一种解决方法是使用默认实例。

package main

import (
"fmt"
)


var defaultFooImpl = &Foo_impl{}

type Foo interface {
    Foo(int) int
}

type Foo_impl struct {
    id int
}

func (f *Foo_impl) Foo(x int) int {
    return x * 2
}



func main() {
    var x *Foo_impl = defaultFooImpl
    constructFoo(x)

    fmt.Println("Hello, playground %v", x)
}

func constructFoo(x Foo) {
    switch value :=x.(type) {
        case *Foo_impl:
            *value = Foo_impl{2}
    }

}

答案 5 :(得分:0)

还有另一种使用可变函数的方法,该方法接受多个指向Foo的nil指针,

package main

import (
"fmt"
)

type Foo interface {
    Foo(int) int
}

type Foo_impl struct {
    id int
}

func (f *Foo_impl) Foo(x int) int {
    return x * 2
}



func main() {
    var x *Foo_impl
    var x1 = []Foo{x}
    constructFoo(x1...)


    fmt.Println("Hello, playground %v", x1[0])
}

func constructFoo(x ...Foo) {
    for i, foo := range x {
        switch  (foo).(type) {
            case *Foo_impl:
                x[i] = &Foo_impl{2}
        }
    }

}