absl/status目录下包含两个Status库
- absl::Status
- absl::StatusOr< T>
absl::Status
在 Google 内部,absl::Status 是跨 API 边界(尤其是跨 RPC 边界)优雅地处理错误的主要机制。其中一些错误可能可以恢复,但其他错误则可能无法恢复。大多数可能产生可恢复错误的函数应设计为返回一个absl::Status 或类似的absl::StatusOr< T>,它保存类型T 的对象或错误。
absl::Status MyFunction(absl::string_view filename, ...) {
...
// encounter error
if (error condition) {
return absl::InvalidArgumentError("bad mode");
}
// else, return OK
return absl::OkStatus();
}
必须被处理的返回值可以标记为ABSL_MUST_USE_RESULT
absl::Status Open(absl::string_view filename, absl::string_view mode, ...) {
if (...) return absl::OkStatus(); // Signal success
if (...) return absl::InvalidArgumentError("bad mode");
absl::Status result; // Default constructor creates an OK value as well.
if (...) {
// Short-hand for result = absl::Status(absl::StatusCode::kNotFound, ...)
result = absl::NotFoundError(absl::StrCat(filename, " is missing"));
} else {
...
}
return result; // could be "OK" or "NOT_FOUND"
}
检查错误返回
处理多个错误代码可能会证明使用 switch 语句是合理的,但仅检查您知道如何处理的错误代码;不要尝试彻底匹配所有规范错误代码。无法处理的错误应被记录和/或传播以供更高级别处理。
如果您确实使用 switch 语句来区分状态代码,请确保还提供 default: switch 大小写,以便代码不会因将其他规范代码添加到 API 而中断。
absl::Status my_status = DoSomething();
// Don't do this:
//
// if (my_status.code() == absl::StatusCode::kOk) { ... }
//
// Use the Status.ok() helper function:
if (!my_status.ok()) {
LOG(WARNING) << "Unexpected error " << my_status;
}
返回一个状态或者一个值
假设函数需要在成功时返回一个值,或者在出错时返回一个状态。 Abseil Status 库为此目的提供了一个 absl::StatusOr< T> 类模板。
StatusOr<Foo> result = Calculation();
if (result.ok()) {
result->DoSomethingCool();
} else {
LOG(ERROR) << result.status();
}
成功后,在调用 ok() 确认 absl::StatusOr< T> 持有 T 类型的对象之后,应通过运算符 * 或运算符-> 来访问由 absl::StatusOr 持有的对象:
absl::StatusOr<int> i = GetCount();
if (i.ok()) {
updated_total += *i;
}
像任何其他指针值一样,absl::StatusOr<T*> 可以从空指针构造,结果将是 ok() 返回 true 并且 value() 返回 nullptr。检查 absl::StatusOr 中指针的值通常需要更加小心,以确保值存在并且该值不为空:
StatusOr<std::unique_ptr<Foo>> result = FooFactory::MakeNewFoo(arg);
if (!result.ok()) {
LOG(ERROR) << result.status();
} else if (*result == nullptr) {
LOG(ERROR) << "Unexpected null pointer";
} else {
(*result)->DoSomethingCool();
}
忽略Status Results
如果忽略函数返回的状态值,我们的编译器会产生错误。在某些情况下,忽略结果是正确的做法,您可以通过使用 IgnoreError() 来实现:
// Don't let caching errors fail the response.
StoreInCache(request, response).IgnoreError();
使用 IgnoreError() 之前请仔细考虑。除非您有充分的理由,否则更愿意实际处理返回值:也许您可以验证结果是否与您期望的错误匹配,或者您可以将其导出以进行监视。
跟踪遇到的第一个错误
例如,假设您要执行两个操作(无论第一个操作是否失败),但希望在其中一个操作失败时返回错误。代替:
absl::Status s = Operation1();
absl::Status s2 = Operation2();
if (s.ok()) s = s2;
使用下面代替
absl::Status s = Operation1();
s.Update(Operation2());