【问题标题】:golang: Using a defined interface in a Map Valuegolang:在映射值中使用定义的接口
【发布时间】:2018-03-08 02:44:54
【问题描述】:

在链接的游乐场示例中,我定义了一个类型:

type DoMap map[int]func(Doer) string

Doer 在我定义的接口类型中的位置。

我在具体类型MyDoer 上实现接口。我希望能够构造一个DoMap,其中该映射的条目包含以下两个函数:

func(Doer) string // this works
func(*MyDoer) string // this doesn't
func(MyDoer) string // more-or-less the same idea, also doesn't

我不能,虽然很明显它们是不同的类型,但我想知道为什么我不能,因为函数确保我必须提供实现 DoerMyDoer

这还不足以确保我履行与该职能的合同吗?

还有其他方法可以实现吗?

https://play.golang.org/p/sJ2Rg3neL7

更新

一些 cmets 的形式是“它们不同”“这就是规范”,但我可以将 MyDoer 传递给接受 Doer 的函数 - 如果实现了接口:为什么将其放入地图改变结果?

更新 2

有一个要求解释“真正的问题”以及为什么我不能只使用类型映射的问题。我会尽力而为:

DoMap 不能是类型映射。我正在编写一个库,该库允许开发人员根据接受开发人员定义的类型(业务消息)的开发人员编写的函数(业务逻辑)的输出,简洁地定义状态机,这些状态机成功或失败转换。图书馆的存在是为了确保一系列转换可以在其他地方进行序列化和记录,然后由图书馆的第三方用户进行验证。我最初并没有这么说,因为它没有抓住重点——没有一个简单的答案。

现在我觉得我的无礼问题惹恼了每个人,而且由于我在快速拨号上没有确切的 Rob Pike,我可能会删除它,除非有人愿意相信我需要做什么我需要做,并提出一些建议。

【问题讨论】:

  • 不,不够,签名不一样。你为什么要这样做? (这可能有助于其他人提出替代方案)。
  • " 我想知道为什么我不能,因为函数确保我必须提供一个实现 Doer 的 MyDoer。"这不会使类型相同。不同的类型是不同的类型。 Go 没有超类型,子类型也是超类型。这就是类型系统的工作原理。
  • Go 并不是真正的面向对象,尽管您可以通过多种方式模仿它。这不是其中之一。
  • 因为你没有传递Doer,你传递的是func(Doer) string,编译器不在乎MyDoer实现Doer,函数类型必须完全匹配。
  • 你已经更新了你的问题,基本上说你理解但不喜欢这个答案。 这就是 Go 的工作原理。 您在 map 中定义了一个特定的值类型,并且您必须使用该类型,句点。超出此范围的任何讨论都超出了 SO 的范围,可能更适合 Go 邮件列表之一。

标签: dictionary go types interface


【解决方案1】:

您还没有概述具体问题(原因)。这使得建议替代方案变得困难,因为看起来您正在尝试在 go 中重新创建另一种语言。

按照优先顺序,您可以按预期使用类型系统:

type DoMap map[int]func(Doer) string

type Doer interface {
    Do() int
    AlsoDo() int
}

https://play.golang.org/p/uPzoOZiLQG

当然也可以绕过类型系统:

type DoMap map[int]interface{}

https://play.golang.org/p/lfKPkwhOGa

但我不建议这样做 - 最好使用语言提供的工具,而不是试图让它们变形。

接口的目的是宣传关于函数的合同——他们需要 this 作为他们的论点,仅此而已。但是你也想在参数上调用 AlsoDo,所以如果你想这样做,把它放在合同中。然后一切都会按您的意愿工作。函数的合同应该像你的例子一样发布在函数旁边,它应该在你的控制之下。

[编辑] 最后,如果你不控制传入的类型,也许你应该重新考虑你的地图的想法。它可能是一个 map[int]Doer,其中 Doer 是一个接口(你应该控制它)。这使您可以在库中宣传您需要的内容,并且用户可以在其中放置他们想要的任何类型(以及他们想要的任何其他依赖项)。

// Library 
type DoMap map[int]Doer

type Doer interface {
    Do() int
}

// Client 
type MyDoer struct {
    myint int
}

func (d *MyDoer) Do() int {
    fmt.Println(d.AlsoDo())
    return d.myint + 1
}

func (d *MyDoer) AlsoDo() int {
    return d.myint + 2
}

https://play.golang.org/p/cs01C8bSKo

[EDIT2] 最后的编辑,如果构建一个 fsm 管理链,你可能会发现这个小项目很有启发性。它绝对应该是可行的,没有太多麻烦,只是不像你第一次尝试可以采用任何类型的函数映射:

https://github.com/ryanfaerman/fsm

【讨论】:

  • 问题是这个映射在库和用户代码之间架起了一座桥梁,所以用户可能想要AlsoDo,但库不知道。
  • 第二个例子提出了一些可能性,但在我的情况下,它只是解决了问题 - 我需要创建一个不知道开发人员定义的具体类型的库,并定义一个使用的映射类型它们,而不需要用户编写类型断言。
  • 也许您应该尝试解释真正的问题,通过编辑上面的答案来解释所有限制。这有点抽象,您关注的是类型系统的限制,而不是您实际需要做的事情。例如,您确定需要作用于类型的函数映射,而不是类型映射吗?
  • 很抱歉,如果我的更新听起来很刻薄,我知道您是真的想提供帮助,谢谢。约束列表不太适合 SO Q&A 格式
  • 你能详细说明为什么map[int]Doer不能用吗?
猜你喜欢
  • 1970-01-01
  • 2017-12-11
  • 2017-12-09
  • 1970-01-01
  • 2015-06-06
  • 1970-01-01
  • 1970-01-01
  • 2022-11-21
  • 1970-01-01
相关资源
最近更新 更多