0

如何编写一个包装库的 Go 包,以便调用被覆盖的函数使用我的实现,而非覆盖函数“落入”我正在包装的库?

特别是:我希望我的 Go 包 wrap net/http,除了我最初只想替换http.FileServerand http.NotFoundHandler,并让所有其他功能保持不变。我的库是现有代码的替代品,它调用了net/http我不会覆盖的其他函数。例如,我希望能够做到:

package main

import (
    "log"
    http "github.com/jstrieb/my-special-http-lib"
)

func main() {
    http.ListenAndServe(                            // Use the net/http ListenAndServe by "falling through" my library
        ":8080", 
        http.FileServer(http.Dir("/usr/share/doc")) // Use my custom, overridden http.FileServer
    )
}

我试过的

我可以手动覆盖包装库导出的每个函数(如下所示),但如果可能的话,我宁愿避免这种情况。这种方法是不可取的,因为它不考虑从我包装的库中调用我覆盖的函数的实例。

func ExportedFunction(input1 type1) type2 {
    return http.ExportedFunction(input1)
}

我也可以完全分叉net/http并直接更改它,但我希望清楚我正在做哪些更改,而无需与原始版本进行比较。维护标准库的一部分以仅覆盖几个函数也是没有意义的。


理由

我不是在寻找关于这是否是一个“好”想法的评论。我只是想知道该怎么做。

这个库的计划是简单地改变 404 页面和目录列表索引页面的外观。这种纯粹的美学变化不会影响net/http. 如果它的结构不是包装所有的net/http,那么用户将不得不在使用两个包之间切换来做同样的事情。那么我的库不能被认为是已经使用net/http.

随着时间的推移,我还打算覆盖更多函数,但我的库的 API 将始终net/http. 这样做可以减少每次库更改时手动http.Function替换调用的需要。mylibrary.Function此外,我希望能够在net/http我没有编写的代码(使用)中导入我的替换,并且不想手动重构。

4

2 回答 2

1

您在这里尝试实现的是扩展包的功能。这里的简单答案是你现在不能这样做。实现这一目标的最佳方法就是手动执行此操作。
就个人而言,我认为将两个包裹分开没有任何害处。我这更易于维护。只需包装您要更新的功能。有时你只需要一个函数。

于 2021-04-29T06:46:58.667 回答
0

不是 Go 专家,但有趣的是,如果通过指定一个依赖项,然后您能够侧加载它的不同版本,而不是进行任何您想要的修改,这将引入一个重大漏洞。

它可能涉及这样一种概念,如果您可以将这种依赖项引入您的应用程序,那么您应该构建一个库,该库构建您要修改的库,然后导入库。也就是说,给定您的应用程序 A 和库 B,以及修改后的库 B',您可能希望编写应用程序,使 A 依赖于 B',而 B' 依赖于 B,这将使关系变得明显。如果你想以某种方式让 A 依赖于 B 但能够动态地侧载 B',那么这将代表我之前提到的漏洞。

于 2021-04-29T19:29:48.057 回答