Google C++每周贴士 #171: 别用哨兵值
2021/7/13 14:08:09
本文主要是介绍Google C++每周贴士 #171: 别用哨兵值,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
(原文链接:https://abseil.io/tips/171 译者:clangpp@gmail.com)
每周贴士 #171: 别用哨兵值
- 最初发布于:2019-11-08
- 作者:Hyrum Wright
- 更新于:2020-04-06
- 短链接:abseil.io/tips/171
哨兵值是指在特定上下文下有特别含义的值。例如,考虑如下API:
// 返回账户余额,如果账户已关闭则返回-5。 int AccountBalance();
除了-5
,每个int
的值都可以是AccountBalance
的合法返回值。直觉上这有点奇怪:调用者是应该特殊地比较-5
,还是说任何负值都能可靠地表示“账户关闭”?要是有一天系统支持余额为负了,API需要调整成为可以返回负值,不就麻爪儿了吗?
使用哨兵值增加了调用端代码的复杂性。如果碰上严谨的调用者,它就会显式地检查哨兵值:
int balance = AccountBalance(); if (balance == -5) { std::cerr << "account closed"; return; } // 在这里使用`balance`
相比之下,有些调用者可能会检查更宽泛的数值:
int balance = AccountBalance(); if (balance <= 0) { std::cerr << "where is my account?"; return; } // 在这里使用`balance`
而有些调用者会直接忽略哨兵值,假设它在实际中根本不会出现。
int balance = AccountBalance(); // 在这里使用`balance`
哨兵值的问题
上面的例子阐明了使用哨兵值的一些常见问题。其他问题还有:
- 不同的系统可能使用不同的哨兵值,例如单个负值,所有负值,无限值,或随便挑的值。沟通特殊值的唯一方式就是文档。
- 哨兵值仍然是对应类型的合法值,所以类型系统对于调用者和被调用者都不会通告数值可能不合法。如果代码和注释不一致,通常两者都是错的(译者注:指API设计得不好)。
- 哨兵值限制了接口的演进,因为特定的哨兵值有一天也许会成为系统的合法值。
- 一个系统的哨兵值是另一个系统的合法值,增加了多系统交互时的认知负担。
忘记检查特定的哨兵值是一个常见漏洞(bug)。在最好的情况下,使用了未经检查的哨兵值会直接在运行时使系统崩溃。更常见的是,未经检查的哨兵值可能会继续在系统里流转,一路产生错误的结果。
改为使用absl::optional
使用absl::optional
而不是特殊值来指示不可用或非法的信息。
// 返回账户余额,如果账户已关闭则返回absl::nullopt absl::optional<int> AccountBalance();
现在我们新版本AccountBalance()
的调用者必须显示地在返回值中检索可能的余额,并在过程中通报结果可能不合法的情况。除非有额外的文档说明,否则调用者可以假设任何合法的int
值都可以被该函数返回,而不用排除特定的哨兵值。这个简化清晰地表明了调用端代码的意图。
absl::optional<int> balance = AccountBalance(); if (!balance.has_value()) { std::cerr << "Account doesn't exist"; return; } // 在这里使用`balance`
下次你在系统中有使用哨兵值的冲动的时候,强烈建议考虑改用适当的absl::optional
。
参见
- 更多关于使用
absl::optional
传递参数的信息,参见每周贴士 #163 - 关于如何决定什么时候该使用
absl::optional
而不是std::unique_ptr
,参见TotW #123。
这篇关于Google C++每周贴士 #171: 别用哨兵值的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-20go-zero 框架的 RPC 服务 启动start和停止 底层是怎么实现的?-icode9专业技术文章分享
- 2024-12-19Go-Zero 框架的 RPC 服务启动和停止的基本机制和过程是怎么实现的?-icode9专业技术文章分享
- 2024-12-18怎么在golang中使用gRPC测试mock数据?-icode9专业技术文章分享
- 2024-12-15掌握PageRank算法核心!你离Google优化高手只差一步!
- 2024-12-15GORM 中的标签 gorm:"index"是什么?-icode9专业技术文章分享
- 2024-12-11怎么在 Go 语言中获取 Open vSwitch (OVS) 的桥接信息(Bridge)?-icode9专业技术文章分享
- 2024-12-11怎么用Go 语言的库来与 Open vSwitch 进行交互?-icode9专业技术文章分享
- 2024-12-11怎么在 go-zero 项目中发送阿里云短信?-icode9专业技术文章分享
- 2024-12-11怎么使用阿里云 Go SDK (alibaba-cloud-sdk-go) 发送短信?-icode9专业技术文章分享
- 2024-12-10搭建个人博客网站之一、使用hugo创建个人博客网站