Golang中如何覆写原结构体的函数?
Golang中如何覆写原结构体的函数?
我有三个包:router、controller、custom
controller 从 custom 导入了一个默认结构体,如果在 controller 包中我创建了一个在 custom 中已存在的函数,那么来自 custom 的 ServeHTTP 应该执行 controller 中的函数,而不是原始的那个。
package router
import "project/controller"
router.Handler("GET", "/service", &controller.Service{})
package controller
import "project/custom"
type Service struct{ custom.PageController }
func (c *Service) Sample() {
fmt.Println("from controller")
}
package custom
type PageController struct {}
func (c *PageController) ServeHTTP(w http.ResponseWriter, r *http.Request) {
c.Sample()
w.Write([]byte("This is my page"))
}
func (c *PageController) Sample(){
fmt.Println("from custom")
}
根据以上解释,我的目标是输出结果为:
"from controller"
但目前的输出是:
"from custom"
更多关于Golang中如何覆写原结构体的函数?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
在这个示例中,它对我来说是有效的。
抱歉,我的示例有点不同;我会检查得更仔细。
更多关于Golang中如何覆写原结构体的函数?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Willy:
我应该在什么时候使用函数和结构体来处理客户端请求。
我认为对此没有严格的规则。这在很大程度上取决于上下文,也许也有一点个人偏好的因素。
感谢你们的回答,让我明白了代码中需要改进的地方。显然,如果我想重写 Sample(),我必须先在 controller 包中重写 ServeHTTP(w http.ResponseWriter, r *http.Request),但这会偏离我的目标。当然,我也可以采纳你们的一些建议,但我了解到,我原本寻求的工作方式类似于其他语言中的继承,而 Go 不应该以这种方式使用,因此我将改变我的项目设计。
但现在我想知道你们对何时更适合使用以下两种选项的看法:
router.Handler("GET", "/service", &controller.Service{})
router.GET("/service", othercontroller.Service())
正如你们所见,区别在于第二个选项接收来自 othercontroller 包的一个函数,而第一个选项接收一个结构体,并且两者都符合以下签名:
ServeHTTP(w http.ResponseWriter, r *http.Request)
我的问题,如果之前没有表达清楚,可以归结为:我应该何时使用函数,何时使用结构体来处理客户端请求。
你好 @Willy,
你的代码无法编译,因为方法 func (c *Controller) Sample() 没有对应的 Controller 类型,你是指 func (c *PageController) Sample() 吗?
为了简化,我将所有包合并成了一个 - Playground 链接
package main
import "fmt"
type PageController struct{}
func (c *PageController) Sample() {
fmt.Println("from custom")
}
type Service struct {
PageController
}
func (c *Service) Sample() {
fmt.Println("from controller")
}
func main() {
s := Service{}
s.Sample() // "from controller"
s.PageController.Sample() // "from custom"
p := PageController{}
p.Sample() // "from custom"
}
s.Sample() 总是 调用 func (c *Service) Sample()。为了调用嵌入字段 PageController 的 Sample() 方法,你需要明确调用路径:s.PageController.Sample()。
@Massimo.Costa 关于接口的例子是实现这类动态行为的一个好方法。
在Go语言中,结构体嵌入不会自动实现多态行为。当PageController的ServeHTTP调用c.Sample()时,它调用的是PageController自己的Sample方法,而不是嵌入结构体的重写版本。
要实现你期望的行为,需要修改ServeHTTP的实现方式。以下是解决方案:
package custom
import (
"fmt"
"net/http"
)
type PageController struct{}
func (c *PageController) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 使用类型断言检查是否有重写的Sample方法
if s, ok := interface{}(c).(interface{ Sample() }); ok {
s.Sample()
} else {
c.Sample()
}
w.Write([]byte("This is my page"))
}
func (c *PageController) Sample() {
fmt.Println("from custom")
}
更好的设计是定义一个接口,并使用接口方法调用:
package custom
import (
"fmt"
"net/http"
)
type Sampler interface {
Sample()
}
type PageController struct{}
func (c *PageController) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 将c转换为Sampler接口
if sampler, ok := interface{}(c).(Sampler); ok {
sampler.Sample()
} else {
c.Sample()
}
w.Write([]byte("This is my page"))
}
func (c *PageController) Sample() {
fmt.Println("from custom")
}
这样,当controller.Service嵌入custom.PageController并重写Sample()方法时,ServeHTTP会调用正确的版本:
package controller
import (
"fmt"
"project/custom"
)
type Service struct {
custom.PageController
}
func (c *Service) Sample() {
fmt.Println("from controller")
}
// Service现在隐式实现了custom.Sampler接口
输出结果将是:
from controller
这个解决方案利用了Go的接口系统,通过类型断言在运行时检查并调用正确的方法实现。

