在Go中,给定一个接口{},我知道它实现了什么接口,如何转换成它

在Go中,给定一个接口{},我知道它实现了什么接口,如何转换成它,go,interface,Go,Interface,我目前的问题是,我正在实现数据结构,并且已经为它们编写了迭代器。我的数据结构、迭代器和所有其他必需的对象都有可见的接口。在后面,我有一些具体的实现,我希望对最终用户隐藏它们 这需要我的许多函数返回接口{}对象,以便我可以存储任何类型的对象(并将验证留给最终用户) 我遇到的一个问题是迭代一个图。我的图实现的迭代器{}返回一个具体的顶点类型,但迭代器接口返回接口{}。由于最终用户只能使用我的基本顶点界面,我必须尝试转换为顶点界面,以便他们可以使用它 这是我在这一点上能想到的最小的例子,它说明了我的问

我目前的问题是,我正在实现数据结构,并且已经为它们编写了迭代器。我的数据结构、迭代器和所有其他必需的对象都有可见的接口。在后面,我有一些具体的实现,我希望对最终用户隐藏它们

这需要我的许多函数返回接口{}对象,以便我可以存储任何类型的对象(并将验证留给最终用户)

我遇到的一个问题是迭代一个图。我的图实现的迭代器{}返回一个具体的顶点类型,但迭代器接口返回接口{}。由于最终用户只能使用我的基本顶点界面,我必须尝试转换为顶点界面,以便他们可以使用它

这是我在这一点上能想到的最小的例子,它说明了我的问题:

package main

import (
    "fmt"
    "strconv"
)

type Base interface {
    Required() string
}

type Concrete struct {
    _data int
}
func (con *Concrete) Required() string {
    return strconv.Itoa(con._data)
}

func convert(val interface{}) *Base {
    if con,ok := val.(*Base); ok {
        return con
    }
    return nil
}

func main() {
    conc := new(Concrete)
    conc._data = 5

    base := convert(conc)

    fmt.Println(base)
}
在上面的代码中,我真的希望convert将类型转换为*Base。函数convert将返回值nil,而不是我希望的可爱值



编辑:删除了未使用的代码,我以为我已经删除了它,但我想没有。现在我已经完成了这篇长篇解释,我有了一个想法并想出了解决方案:

func convert(val interface{}) Base {
    if con,ok := val.(Base); ok {
        return con
    }
    return nil
}
不要试图强制转换到指针,而只是转换到基接口

我不知道为什么会这样。当我在convert中执行reflect.TypeOf(val)时,它会给出输出

*main.Concrete

我希望其他人觉得这很有用,并且其他人可以回答这个答案的为什么部分。

现在我已经完成了这篇长篇解释,我有了一个想法并找到了解决方案:

func convert(val interface{}) Base {
    if con,ok := val.(Base); ok {
        return con
    }
    return nil
}
不要试图强制转换到指针,而只是转换到基接口

我不知道为什么会这样。当我在convert中执行reflect.TypeOf(val)时,它会给出输出

*main.Concrete

我希望其他人会觉得这很有用,也希望其他人能回答这个答案的为什么部分。

你几乎不想使用指向接口的指针。例如,
*bytes.Buffer
(指向结构类型的指针)很常见,但
*io.Reader
几乎总是一个错误。要真正理解为什么可能需要阅读以下内容:。@DaveC感谢您提供的链接,我们将查看它。让我感到困惑的一件事是,如果我想将指向某个结构的指针转换为接口,那么我不会将它作为指针保留。我的一个问题是指针部分发生了什么。如何将指针转换为非指针类型/接口?在该链接中已详细说明。接口值将指向任何底层类型,如果它是
*具体的
,就这样吧。指向接口的指针不能实现该接口(例如
func f(r io.Reader,rp*io.Reader)
可以调用
r.Read
,但不能调用
rp.Read
)。您几乎不想使用指向接口的指针。例如,
*bytes.Buffer
(指向结构类型的指针)很常见,但
*io.Reader
几乎总是一个错误。要真正理解为什么可能需要阅读以下内容:。@DaveC感谢您提供的链接,我们将查看它。让我感到困惑的一件事是,如果我想将指向某个结构的指针转换为接口,那么我不会将它作为指针保留。我的一个问题是指针部分发生了什么。如何将指针转换为非指针类型/接口?在该链接中已详细说明。接口值将指向任何底层类型,如果它是
*具体的
,就这样吧。指向接口的指针没有实现该接口(例如,
func f(r io.Reader,rp*io.Reader)
可以调用
r.Read
,但不能调用
rp.Read
)。如果你看一下,你会发现你的
convert
函数只是
base,
。它将根据需要返回零值(指针为nil)。但是,很少需要忽略布尔值。如果您的代码期望它是唯一添加元素的东西,那么使用
base:=conc.(base)
是合适的。当运行时检测到代码中的错误时,您希望运行时死机,就像失败的片/数组边界检查会死机一样。@DaveC我之所以有一个方法,是因为我在几个地方调用了它。如果我改变了基础类型,我不想在很多地方改变它。我离开布尔检查的唯一原因是因为我喜欢它的外观。如果你看看,你会看到你的
convert
函数就是
base,:=conc.(base)
。它将根据需要返回零值(指针为nil)。但是,很少需要忽略布尔值。如果您的代码期望它是唯一添加元素的东西,那么使用
base:=conc.(base)
是合适的。当运行时检测到代码中的错误时,您希望运行时死机,就像失败的片/数组边界检查会死机一样。@DaveC我之所以有一个方法,是因为我在几个地方调用了它。如果我改变了基础类型,我不想在很多地方改变它。我离开布尔检查的唯一原因是因为我喜欢它的外观。