Golang中如何使用接口实现包之间的最佳交互方式

Golang中如何使用接口实现包之间的最佳交互方式 我正在寻找如何绑定两个包的解决方案。 我做了一个示例(可惜它无法运行)

Go Playground Go Playground - The Go Programming Language

这会产生一个错误:

# play.ground
./prog.go:11:15: cannot use dlg (type dialog.Dialog) as type config.dialog in argument to cfg.SetDialog:
dialog.Dialog does not implement config.dialog (wrong type for SetGlobalConfig method)
have SetGlobalConfig(dialog.Config)
want SetGlobalConfig(config.Config)

我学习的主要相关链接:

Go 语言规范 The Go Programming Language Specification - The Go Programming Language

CodeReviewComments CodeReviewComments

据我理解,原因是:

已定义的类型 总是与其他任何类型都不同。

我查看了这里的示例 CodeReviewComments · golang/go Wiki · GitHub,没发现和我做的有什么不同。我尝试通过移除 SetGlobalConfig 函数中的参数来简化逻辑,然后它就能工作了。 Go Playground - The Go Programming Language 但在这种情况下,我无法将配置实例发送到对话框,反之亦然。

所以问题是——是否存在一种解决方案可以在包之间传递对象?


更多关于Golang中如何使用接口实现包之间的最佳交互方式的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

我尝试使用您提供的示例,但很难理解各部分是如何配置的,因此我在此整理了一个不同的示例:https://play.golang.org/p/dq9eB2DXArI

更多关于Golang中如何使用接口实现包之间的最佳交互方式的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我现在在手机上,无法立即深入查看,但我认为你需要使用接口类型作为你的 Config 类型;它不能是结构体。

我几小时前回答了一个相关问题此处。请查看关于接口类型以及我在示例中使用的 myReader 类型部分。

你好,Sean,感谢你在相关帖子中给出的详尽解释!我注意到,核心类型大多操作的是标准类型,例如 boolintstring 等。那么如果我们想使用一些自定义的外部类型呢?我们确实希望在同一个包中进行复制/实现。我想接口在这里会有所帮助。这实际上正是我试图在我的代码中实现的。

我认为你必须使用接口类型作为你的 Config 类型;它不能是结构体。

能否请你简要举例说明一下你会如何实现这一点?

非常感谢你提供的示例,这非常有价值!

你的示例在接口中使用了简单的类型。我尝试处理一个包含来自不同包的属性类型的类型,并尝试使用接口来实现。看起来,这似乎是错误的。

Go 只有一种从根路径到包的访问方式。我的想法是使用根包作为两个包之间的通信中介,但每个包理论上只知道另一个包的存在,因此逻辑保留在相关的包中。如果这是错误的,那就意味着只有根包可以操作子包,而包之间甚至不能使用接口进行交互。

在 Go 中,是否有构建正确应用程序架构的最佳实践?这不是我第一次尝试构建一个 Go 小项目来加深理解,而每次对接口的理解都阻碍了我。我来自 PHP 世界,我理解经典 OOP 和 Go 中接口的区别,但我找不到应用程序架构设计的严格方法。你有什么建议吗?

在Go中,接口是实现包之间解耦交互的最佳方式。你的问题源于类型定义不同,即使底层结构相同,dialog.Configconfig.Config也被视为不同的类型。

解决方案:使用共享接口

1. 创建共享接口包(推荐)

创建一个独立的包来定义接口:

// shared/interfaces.go
package shared

type Config interface {
    GetValue() string
    SetValue(string)
}

type Dialog interface {
    SetGlobalConfig(Config)
    Show()
}

2. 在各包中实现接口

// config/config.go
package config

import "shared"

type MyConfig struct {
    value string
}

func (c *MyConfig) GetValue() string {
    return c.value
}

func (c *MyConfig) SetValue(v string) {
    c.value = v
}

func NewConfig() shared.Config {
    return &MyConfig{}
}
// dialog/dialog.go
package dialog

import "shared"

type MyDialog struct {
    config shared.Config
}

func (d *MyDialog) SetGlobalConfig(cfg shared.Config) {
    d.config = cfg
}

func (d *MyDialog) Show() {
    // 使用配置
    if d.config != nil {
        println("Config value:", d.config.GetValue())
    }
}

func NewDialog() shared.Dialog {
    return &MyDialog{}
}

3. 主程序中使用

package main

import (
    "config"
    "dialog"
    "shared"
)

func main() {
    // 创建配置
    cfg := config.NewConfig()
    cfg.SetValue("Hello from config")
    
    // 创建对话框
    dlg := dialog.NewDialog()
    
    // 设置配置 - 现在可以正常工作
    dlg.SetGlobalConfig(cfg)
    
    // 显示对话框
    dlg.Show()
}

替代方案:使用嵌入和类型断言

如果不想创建单独的接口包:

// config/config.go
package config

type Config interface {
    GetValue() string
    SetValue(string)
}

type MyConfig struct {
    value string
}

func (c *MyConfig) GetValue() string {
    return c.value
}

func (c *MyConfig) SetValue(v string) {
    c.value = v
}
// dialog/dialog.go
package dialog

import "config"

type Dialog interface {
    SetGlobalConfig(config.Config)
    Show()
}

type MyDialog struct {
    config config.Config
}

func (d *MyDialog) SetGlobalConfig(cfg config.Config) {
    d.config = cfg
}

关键点

  1. 接口定义位置:接口应该定义在使用它的地方,而不是实现它的地方
  2. 避免循环依赖:通过接口解耦包之间的依赖
  3. 最小接口原则:只暴露必要的方法

你的错误是因为dialog.Configconfig.Config虽然结构相同,但Go编译器将它们视为完全不同的类型。通过共享接口,可以解决这个问题。

回到顶部