Go 如何为指向不同结构的指针实现相同的函数?

Go 如何为指向不同结构的指针实现相同的函数?,go,struct,interface,Go,Struct,Interface,假设我有很多不同的结构,但它们都共享一个公共字段,例如“name”。例如: 类型foo struct{ 名称字符串 其他字符串 //其他领域 } 类型栏结构{ 名称字符串 数字整数 //其他领域 } 在程序中,我反复遇到这样的情况:我得到指向这些结构的指针(so*foo、*bar等),需要根据指针是否为零执行操作,基本上如下所示: func-worknname(f*foo)接口{{ 如果(f==nil){ //做很多事情 }否则{ //做很多其他的事情 } //做更多的事情 归还某物 } 此

假设我有很多不同的结构,但它们都共享一个公共字段,例如“name”。例如:

类型foo struct{
名称字符串
其他字符串
//其他领域
}
类型栏结构{
名称字符串
数字整数
//其他领域
}
在程序中,我反复遇到这样的情况:我得到指向这些结构的指针(so*foo、*bar等),需要根据指针是否为零执行操作,基本上如下所示:

func-worknname(f*foo)接口{{
如果(f==nil){
//做很多事情
}否则{
//做很多其他的事情
}
//做更多的事情
归还某物
}
此函数仅使用
名称
,在所有结构中都是相同的。如果这些不是指针,我知道我可以为每个返回名称的结构编写一个公共接口,并将其用作类型。但对于指针,所有这些都不起作用。Go要么在编译时抱怨,要么nil检查不起作用,导致恐慌。我没有发现比为我拥有的每个结构复制/粘贴完全相同的代码更聪明的方法,因此基本上要实现所有功能:

func(f*foo)workNName()接口{}
func(b*bar)workNName()接口{}
func(h*ham)workNName()接口{}
//等等。。。
有没有更好的方法可以做到这一点,也就是说,只为我所有的结构实现一个简单的函数(甚至更好,根本没有函数),只为所有的结构编写一次复杂的东西

编辑:感谢您提供到目前为止的答案,但只需使用以下类型的界面:

func(f foo)Name()字符串{
返回f.name
}

对于某些提供
Name()
的接口,由于指针未被识别为nil,因此无法工作。请参见以下内容:

您可以声明一个接口,该接口声明一个返回名称的函数:

type WithName interface {
    Name() string
}
为了实现该接口,键入(
foo
bar
,等等)需要有该方法,而不仅仅是字段和方法

func (f foo) Name() string {
    return f.name
}
然后,
workNName
需要接收该接口的引用:

func workOnName(n WithName) interface{} {
    if (n == nil || reflect.ValueOf(n).isNil()) {
        // Do lots of stuff
    } else {
        // Do lots of other stuff
    }
    // Do even more stuff
    return something
}

请记住,参数
n with name
始终被视为指针,而不是对象值。

您可以声明一个接口,该接口声明一个返回名称的函数:

type WithName interface {
    Name() string
}
为了实现该接口,键入(
foo
bar
,等等)需要有该方法,而不仅仅是字段和方法

func (f foo) Name() string {
    return f.name
}
然后,
workNName
需要接收该接口的引用:

func workOnName(n WithName) interface{} {
    if (n == nil || reflect.ValueOf(n).isNil()) {
        // Do lots of stuff
    } else {
        // Do lots of other stuff
    }
    // Do even more stuff
    return something
}

请记住,参数
n with name
始终被视为指针,而不是对象值。

我认为
reflect
就是这种情况

比如:

主程序包
进口(
“fmt”
“反映”
)
func SetFieldX(obj,值接口{}){
v:=reflect.ValueOf(obj).Elem()
如果!v.IsValid(){
fmt.Println(“目标为零”)
返回
}
f:=v.FieldByName(“X”)
如果f.IsValid()&&f.CanSet(){
f、 集合(反映.值of(值))
}
}
func main(){
st1:=&struct{X int}{10}
var stNil*结构{}
SetFieldX(ST1555)
SetFieldX(stNil,“SSS”)
fmt.Printf(“%v\n%v\n”,st1,stNil)
}


请注意,
IsValid
检查的不仅仅是
obj==nil
,但是如果您真的想区分
nil指针和非结构对象的情况,您可以自由地实现它。

我认为
reflect
就是这种情况

比如:

主程序包
进口(
“fmt”
“反映”
)
func SetFieldX(obj,值接口{}){
v:=reflect.ValueOf(obj).Elem()
如果!v.IsValid(){
fmt.Println(“目标为零”)
返回
}
f:=v.FieldByName(“X”)
如果f.IsValid()&&f.CanSet(){
f、 集合(反映.值of(值))
}
}
func main(){
st1:=&struct{X int}{10}
var stNil*结构{}
SetFieldX(ST1555)
SetFieldX(stNil,“SSS”)
fmt.Printf(“%v\n%v\n”,st1,stNil)
}


请注意,
IsValid
检查的不仅仅是
obj==nil
,但是如果您真的想区分
nil指针
和非结构对象的情况,您可以自由地实现它。

如果它只使用
name
字段,为什么它要将整个结构作为参数,而不仅仅是名称?i、 e.只要有一个函数
workanname(name string)
@Adrian在本例中,它只使用名称,我使用它是为了说明。实际问题包含大约10个使用的字段。此外,指针是否为零的检查必须在某个地方进行,因此,如果指针不在函数(它所属的位置)中进行,这意味着要在几十个地方检查指针是否为零。您的问题是“此函数只使用名称,在所有结构中都是相同的”-您的注释,“大约使用了10个字段”这意味着一个非常不同的问题。我可能希望更改模型,这样字段就不会重复,而是使用一个带有共享字段的嵌入式结构,然后编写
workannaimdstuff
函数来获取嵌入式类型。但是,如果没有看到实际相关的示例代码,就很难提供太多建议。@MarkAnderson如果函数只需要名称即可完成其工作,为什么不将name字段而不是整个结构传递给函数?@MarkAnderson您可以使用reflect来确定非nil接口的值是否为nil如果它只使用
name
字段,为什么它将整个结构作为参数而不是仅取名称?i、 e.只要有一个函数
workanname(name string)
@Adrian在本例中,它只使用名称,我使用它是为了说明。实际问题包含大约10个使用的字段。此外,检查w