• 6.1. 设计难以被误用的 API
  • 6.1.1. 警惕采用几个相同类型参数的函数

    6.1. 设计难以被误用的 API

    APIs should be easy to use and hard to misuse. (API 应该易于使用且难以被误用) — Josh Bloch [3]

    如果你从这个演讲中带走任何东西,那应该是 Josh Bloch 的建议。 如果一个 API 很难用于简单的事情,那么 API 的每次调用都会很复杂。 当 API 的实际调用很复杂时,它就会便得不那么明显,而且会更容易被忽视。

    6.1.1. 警惕采用几个相同类型参数的函数

    简单, 但难以正确使用的 API 是采用两个或更多相同类型参数的 API。 让我们比较两个函数签名:

    1. func Max(a, b int) int
    2. func CopyFile(to, from string) error

    这两个函数有什么区别? 显然,一个返回两个数字最大的那个,另一个是复制文件,但这不重要。

    1. Max(8, 10) // 10
    2. Max(10, 8) // 10

    Max 是可交换的; 参数的顺序无关紧要。 无论是 8 比 10 还是 10 比 8,最大的都是 10。

    但是,却不适用于 CopyFile

    1. CopyFile("/tmp/backup", "presentation.md")
    2. CopyFile("presentation.md", "/tmp/backup")

    这些声明中哪一个备份了 presentation.md,哪一个用上周的版本覆盖了 presentation.md? 没有文档,你无法分辨。 如果没有查阅文档,代码审查员也无法知道你写对了顺序。

    一种可能的解决方案是引入一个 helper 类型,它会负责如何正确地调用 CopyFile

    1. type Source string
    2. func (src Source) CopyTo(dest string) error {
    3. return CopyFile(dest, string(src))
    4. }
    5. func main() {
    6. var from Source = "presentation.md"
    7. from.CopyTo("/tmp/backup")
    8. }

    通过这种方式,CopyFile 总是能被正确调用 - 还可以通过单元测试 - 并且可以被设置为私有,进一步降低了误用的可能性。

    贴士: 具有多个相同类型参数的API难以正确使用。