如何只做一些修改就封装一个 Go 包? 我尝试了什么理由

问题描述

如何编写封装库的 Go 包,以便调用覆盖函数使用我的实现,而未覆盖函数“落入”到我要封装的库中?

特别是:我希望我的 Go 包包装 net/http,除了我最初只想替换 http.FileServerhttp.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 source 并直接对其进行更改,但我希望无需与原始版本进行比较即可清楚我正在进行哪些更改。维护部分标准库的分支以仅覆盖少数函数也是没有意义的。


理由

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

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

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

解决方法

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

,

不是 Go 专家,但顺便说一句,这会引入一个重大漏洞,如果通过指定一个依赖项,您就可以侧载它的不同版本而是进行您想要的任何修改。

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