像 C++ 和 Rust 这样的语言有一个 Option 类型,它基本上是一个带有值的枚举/布尔值。
但我觉得这可能会出现一些问题,例如:
那么为什么不将 bool 值与值放在一起,而是使用一个与类型关联的函数来检查返回的值是否有效。
例如:
template<typename T, bool(*ISOK)(T&)>
struct Errorable
{
private:
T val;
public:
Errorable(T v)
{
val = v;
}
bool is_ok()
{
return ISOK(val);
}
bool is_err()
{
return !ISOK(val);
}
T unwrap_or(T o)
{
if(ISOK(val))
return val;
return o;
};
T unwrap_forced()
{
return val;
}
};
可以这样使用:
bool idx_ok(int& idx)
{
return idx >= 0;
}
Errorable<int, idx_ok> array_idx_of(int *arr, int len, int elm)
{
for(int i = 0 ; i < len ; i++)
{
if(arr[i] == elm)
{
Errorable<int, idx_ok> ok(i);
return ok;
}
}
Errorable<int, idx_ok> err(-1);
return err;
}
然后
int main()
{
int arr[5] = {1, 2, 3, 4, 5};
auto idx = array_index_of(arr, 5, 6);
if(idx.is_ok())
{ ... }
}
抱歉,如果我的 C++ 不好,我是一名需要模板的 C 程序员
如果您的函数可以返回值或“无值”,那么请随意使用
std::optional
:
std::optional<int> tryToGetValue() {
if (condition) return 100;
else return std::nullopt;
}
如果您的函数总是返回一些值/结构,但是结构不变量并不总是满足,请返回带有验证函数的结构(您可以将其概括为提供自定义验证器,使用多态性等):
struct JsonResponse {
bool isValid();
int getValue(/* some args */);
// some logic
};
JsonResponse requestReply(/* ... */);
如果您的函数应该始终返回一个值,并且如果该值无效,则继续其余的程序逻辑是没有意义的,则抛出异常:
int getElement(int idx) {
if (container.size() <= idx) throw std::logic_error("idx out of bounds");
}
尝试始终优先考虑语义,并编写表达意图的代码。然后(仅限专家!)您可以尝试对其进行分析并优化。