如何以惯用方式构建现有包的扩展
How to build extensions to existing packages idiomatically
Effective Go 和许多其他维基和站点,劝告 Go 程序员使用简单的包名称,避免使用过于笼统的名称,例如 'misc' 或 'utils'。
此外,Go 避开了多级命名空间——它只有一层——包名。
所以,包名要简单,最多一两个词组合,要有针对性。
然后没有办法将新代码注入现有包,所以 'os' 中的内容基本上是由我碰巧选择的任何版本的包 'os' 的作者密封的使用(很可能是 Go os
包)。
但这就是我摸不着头脑的地方。
我如何编写一个自己的好库,将现有的 concepts/packages(例如 os
或 fmt
或像 "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"后缀。示例:
有几种方法可以解决这个问题。
首先,尽管不鼓励,但 misc
、helpers
、api
包存在于许多项目中。
如果您正在为现有包 something
编写扩展,您可以将新包命名为 somethingext
。
您可以通过依赖您的用户正确使用别名来使用多级命名:
import (
"os"
osutils "github.com/someproject/os"
)
如果您正在编写现有包 something
的替代品,您可以将您的包命名为 something
,类似于 github.com/sirupsen/logrus
,它是 stdlib log
的替代品] 包裹。
在非常简单的情况下,我不介意在我的项目中有 utils
个包。如果函数调用是显式的,例如 utils.GetEnvOrDefault
,我发现它仍然易于阅读和理解。
但是让我们考虑一个更复杂的情况。您提到在包中使用公司名称,如 organization_os
。这确实使代码更难阅读。
包名也可以自文档化。 enviroment.GetEnvOrDefault
可能是一个选项。如果名称太大,您始终可以将导入别名改成更简洁的名称。
Effective Go 和许多其他维基和站点,劝告 Go 程序员使用简单的包名称,避免使用过于笼统的名称,例如 'misc' 或 'utils'。
此外,Go 避开了多级命名空间——它只有一层——包名。
所以,包名要简单,最多一两个词组合,要有针对性。
然后没有办法将新代码注入现有包,所以 'os' 中的内容基本上是由我碰巧选择的任何版本的包 'os' 的作者密封的使用(很可能是 Go os
包)。
但这就是我摸不着头脑的地方。
我如何编写一个自己的好库,将现有的 concepts/packages(例如 os
或 fmt
或像 "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"后缀。示例:
有几种方法可以解决这个问题。
首先,尽管不鼓励,但 misc
、helpers
、api
包存在于许多项目中。
如果您正在为现有包 something
编写扩展,您可以将新包命名为 somethingext
。
您可以通过依赖您的用户正确使用别名来使用多级命名:
import (
"os"
osutils "github.com/someproject/os"
)
如果您正在编写现有包 something
的替代品,您可以将您的包命名为 something
,类似于 github.com/sirupsen/logrus
,它是 stdlib log
的替代品] 包裹。
在非常简单的情况下,我不介意在我的项目中有 utils
个包。如果函数调用是显式的,例如 utils.GetEnvOrDefault
,我发现它仍然易于阅读和理解。
但是让我们考虑一个更复杂的情况。您提到在包中使用公司名称,如 organization_os
。这确实使代码更难阅读。
包名也可以自文档化。 enviroment.GetEnvOrDefault
可能是一个选项。如果名称太大,您始终可以将导入别名改成更简洁的名称。