Golang中为什么无法在实现接口的结构体新实例上调用接口函数?

Golang中为什么无法在实现接口的结构体新实例上调用接口函数? 为什么

builder := aliasBuilder{}
 return builder.From(c.GetString("from")).To(c.GetString("to"))

能够编译并运行,但是

return aliasBuilder{}.From("this").To("that") //<- 不能运行?

如果存在一种方法让单行版本“运行”,那么它的语法会是什么样子?

以下是更完整的代码上下文。

type Alias struct {
	From uuid.UUID
	To   uuid.UUID 
}

func Create(c *gin.Context) domain.Alias {
  	builder := aliasBuilder{}
   	return builder.From(c.GetString("from")).To(c.GetString("to"))
}

type aliasBuilder struct {
	from uuid.UUID
	tb toBuilder
}

type toBuilder struct {
	fb *aliasBuilder
	touid uuid.UUID
}

type to interface {
	To(to string) uuid.UUID
}

type from interface {
	From(from string) to
}

func (fb *aliasBuilder) From(from string) *toBuilder {
	fb.from = uuid.FromStringOrNil(from)
	fb.tb = toBuilder{fb: fb}
	return &fb.tb
}

func (tb *toBuilder) To(tot string) domain.Alias {
	tb.touid = uuid.FromStringOrNil(tot)
	return domain.NewAlias(tb.fb.from, tb.touid)
}

更多关于Golang中为什么无法在实现接口的结构体新实例上调用接口函数?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

6 回复

因为你的接口需要一个指针接收器,而结构体字面量不能用作指针接收器。

更多关于Golang中为什么无法在实现接口的结构体新实例上调用接口函数?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


感谢您花时间解释这一点。内联正确地处理引用/解引用确实很棘手。

将你的实现改为使用非指针接收器,例如:

func (tb toBuilder) To(tot string) domain.Alias {
    // ...
}

那么,我应该如何指定才能获得我想要的语法呢。

return aliasBuilder{}.From("this").To("that")

除了NobbZ的建议,你也可以这样写:

return (&aliasBuilder{}).From("this").To("that")

例如:

https://play.golang.org/p/rXDdGBfwir-

在Go语言中,你的第二个示例无法编译是因为aliasBuilder{}.From("this")返回的是*toBuilder指针,但aliasBuilder{}是一个临时值(非地址),其方法接收器是指针类型。

问题分析:

  1. From方法的接收器是*aliasBuilder(指针类型)
  2. aliasBuilder{}创建的是结构体值,不是指针
  3. 值类型不能调用指针接收器的方法,除非它是可寻址的

解决方案有以下几种:

方案1:使用指针创建

return (&aliasBuilder{}).From("this").To("that")

方案2:使用new函数

return new(aliasBuilder).From("this").To("that")

方案3:定义返回指针的构造函数

func newAliasBuilder() *aliasBuilder {
    return &aliasBuilder{}
}

// 使用
return newAliasBuilder().From("this").To("that")

方案4:修改方法接收器为值类型(不推荐,会破坏你的构建器模式)

func (fb aliasBuilder) From(from string) *toBuilder {
    fb.from = uuid.FromStringOrNil(from)
    fb.tb = toBuilder{fb: &fb}
    return &fb.tb
}

在你的完整代码上下文中,正确的单行版本应该是:

return (&aliasBuilder{}).From(c.GetString("from")).To(c.GetString("to"))

这是因为Go语言中,只有可寻址的值才能调用指针接收器的方法。aliasBuilder{}作为临时值是不可寻址的,而(&aliasBuilder{})new(aliasBuilder)创建的是指针,可以直接调用指针接收器的方法。

回到顶部