gpt4 book ai didi

父结构上的 Golang 嵌入式接口(interface)

转载 作者:IT王子 更新时间:2023-10-29 00:34:27 25 4
gpt4 key购买 nike

我有一个程序试图在“子类”上实现功能,父类可以在其中检查接口(interface)是否已实现。从角度来看,它实际上是在处理基于是否存在方法的 REST URL 生成。

我遇到的是基于以下模式,IList 和 IGet 接口(interface)都在 TestController 对象上找到,而只有 1 个被实现。当调用 IGet 接口(interface)时,我会感到 panic 。

我宁愿不在基本结构上对 Get/List 进行具体定义,然后必须覆盖它们,宁愿先测试是否存在,然后再从那里开始。

这里还有一个 go playground 链接 https://play.golang.org/p/5j58fejeJ3

package main

import "fmt"

type IGet interface {
Get(int)
}

type IList interface {
List(int)
}

type Application struct {
name string
}

type BaseAppController struct {
*Application

IGet
IList
}

type TestController struct {
*BaseAppController
}

func (ctrl *BaseAppController) Init() {
fmt.Println("In Init")

if f, ok := interface{}(ctrl).(IGet); ok {
fmt.Println("Controller Found GET", f)
} else {
fmt.Println("Controller NOT Found GET", f)
}

if f, ok := interface{}(ctrl).(IList); ok {
fmt.Println("Controller Found LIST", f)
} else {
fmt.Println("Controller NOT Found LIST", f)
}
}

func (ctrl *BaseAppController) Call() {
fmt.Println("In Call")

if f, ok := interface{}(ctrl).(IGet); ok {
fmt.Println("Controller Found GET - going to call", f)

f.Get(7)
} else {
fmt.Println("Controller NOT Found GET - can't call", f)
}
}

// Test controller implements the Get Method
func (ctrl *TestController) Get(v int) {
fmt.Printf("Hi name=%s v=%d\n", ctrl.name, v)
}

func main() {
app := Application{"hithere"}
ctrl := TestController{&BaseAppController{Application: &app}}

ctrl.Init()

ctrl.Call()
}

最佳答案

您似乎缺少的一件事是嵌入接口(interface)如何影响 Go 中的结构。看,嵌入将嵌入类型(结构或接口(interface),无关紧要)的所有方法提升为父类型的方法,但使用嵌入对象作为接收者调用。

实际的副作用是,将接口(interface)嵌入到结构中可以保证该结构实现其嵌入的接口(interface),因为根据定义,它具有该接口(interface)的所有方法。然而,尝试调用任何这些方法而不定义一些东西来填充结构中的接口(interface)字段,将会出现 panic ,因为该接口(interface)字段默认为 nil

因此,您的类型断言将始终为真。 BaseAppController 嵌入了 IGetIList 接口(interface),因此总是满足这两个接口(interface)。

如果你想要 duck-typing,根据类型上是否存在方法有选择地启用行为,你需要使用类似于标准库 io.WriterTo interface 工作方式的东西。此接口(interface)和 io.ReaderFrom 是可选接口(interface),io.Writerio.Reader 对象可以实现以直接写入或从另一个源读取,而不是 io 包需要缓冲读取数据或要写入的数据本身。

基本要点是您定义一个底层接口(interface),其中包含必需的 方法,这就是您传递的内容。然后您有一个或多个可选接口(interface),您可以检查传递的类型以查看它们是否满足,如果满足,则使用该可选接口(interface)的方法(如果不满足,则恢复为默认行为)。在这种情况下不需要嵌入。

接口(interface)的嵌入,而不是为了鸭子类型,更多的是关于多态性。例如,如果您想访问 SQL 数据库,但又希望能够处理标准数据库调用和事务中的调用,您可以创建一个结构来保存两种类型( sql.DBsql.Tx )的联​​合方法,例如这个:

type dber interface {
Query(query string, args ...interface{}) (*sql.Rows, error)
QueryRow(query string, args ...interface{}) *sql.Row
Exec(query string, args ...interface{}) (sql.Result, error)
}

然后你做一个这样的结构:

type DBHandle struct {
dber
}

现在,您可以在该sql.DBsql.Tx中存储结构的dber,以及使用DBHandle的任何内容(以及所有方法(以及所有方法它们是否在事务范围内被调用(但是请记住,必须首先初始化该接口(interface)字段!)

这种类型的功能是嵌入真正开始发挥作用的地方,因为它允许功能和灵 active 接近完全多态继承系统,而无需显式“实现”或“扩展”语句。对于您想要的动态鸭子键入行为类型,它并不是很有用。

关于父结构上的 Golang 嵌入式接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38043678/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com