如何以惯用方式构建现有包的扩展

How to build extensions to existing packages idiomatically

Effective Go 和许多其他维基和站点,劝告 Go 程序员使用简单的包名称,避免使用过于笼统的名称,例如 'misc' 或 'utils'。

此外,Go 避开了多级命名空间——它只有一层——包名。

所以,包名要简单,最多一两个词组合,要有针对性。

然后没有办法将新代码注入现有包,所以 'os' 中的内容基本上是由我碰巧选择的任何版本的包 'os' 的作者密封的使用(很可能是 Go os 包)。

但这就是我摸不着头脑的地方。

我如何编写一个自己的好库,将现有的 concepts/packages(例如 osfmt 或像 "extends map types" 这样通用的东西扩展到一个包中或在我自己的项目(或我的组织,或者可能及时公开)之间共享的一组包?

作为一个任意的例子,假设我通常需要一个函数,例如 GetEnvOrDefault(key, def string) string

这很有用。它可以写成一组 if 语句,但它是自文档化的,一次写起来稍微短一些,并且允许客户端代码使用,并且在它们的含义上更短和更简洁(对 [= 的视觉解析较少58=] 与一遍又一遍地拼写代码 - 在这种情况下:

// GetEnvOrDefault returns the specified environment variable's contents, or the specified default value if that env var is not present
func GetEnvOrDefault(key, defvalue string) string {
    value := os.Getenv(key)
    if len(value) == 0 {
        value = defvalue
    }
    return value
}

这只是一个例子。它很短以便适合这里并且易于讨论。我要冒险,假设你能想到一个任意的、更复杂的例子,毫无疑问你想把它放在一个库中以便编写和调试一次,然后有多个项目使用和使用此类功能。

给这个包起什么名字?

不是 'utils' 也不是 'misc' 因为这在 Go 中太天哪了。 不能 'os' 因为它被有效地密封了。 不能 'organization/os' 因为我们不能做多级命名空间。 不应该是 'organization_os' 因为这不是 Go 的惯用语。

那我们会怎样呢?

'osx' - 呃... 'osex' - 有趣但是... 'osmisc' - 看起来很丑/不好... 'env' - 好的,当然,但那是超级通用的 - 我敢打赌已经有更多的包更配得上这个名字,将来会发生冲突......

你感觉到我了吗?

这是一个例子。但是我对 JSON、uuid、地图、32 位数学、http 服务器、http 客户端、...

进行了有用的扩展

程序员做什么的?

复制这样的小杂项。每个项目的实用函数和类型?

想出非常不惯用的包名称?

您有什么建议?

标准库使用"util"后缀。示例:

有几种方法可以解决这个问题。

首先,尽管不鼓励,但 mischelpersapi 包存在于许多项目中。

如果您正在为现有包 something 编写扩展,您可以将新包命名为 somethingext

您可以通过依赖您的用户正确使用别名来使用多级命名:

import (
   "os"
   osutils "github.com/someproject/os"
)

如果您正在编写现有包 something 的替代品,您可以将您的包命名为 something,类似于 github.com/sirupsen/logrus,它是 stdlib log 的替代品] 包裹。

在非常简单的情况下,我不介意在我的项目中有 utils 个包。如果函数调用是显式的,例如 utils.GetEnvOrDefault,我发现它仍然易于阅读和理解。

但是让我们考虑一个更复杂的情况。您提到在包中使用公司名称,如 organization_os。这确实使代码更难阅读。

包名也可以自文档化。 enviroment.GetEnvOrDefault 可能是一个选项。如果名称太大,您始终可以将导入别名改成更简洁的名称。