This is kind of可能,但通常不是一个好主意,尤其是在您的示例中(我稍后会解释)。
您不能轻易退货String
和做?
返回默认值,但您可以定义自己的字符串类型并实现std::ops::Try为了它。注意Try
还是不稳定!
让我们看看这是如何工作的:
// Just wrap a string
struct StringlyResult {
s: String,
}
// Convenience conversion
impl From<String> for StringlyResult {
fn from(s: String) -> Self {
Self { s }
}
}
// The impl that allows us to use the ? operator
impl std::ops::Try for StringlyResult {
type Ok = String;
type Error = String;
fn into_result(self) -> Result<Self::Ok, Self::Error> {
if self.s == "No parameters named pass" {
Err(self.s)
} else {
Ok(self.s)
}
}
fn from_error(s: Self::Error) -> Self {
if s != "No parameters named pass" {
panic!("wat");
}
Self { s }
}
fn from_ok(s: Self::Ok) -> Self {
if s == "No parameters named pass" {
panic!("wat");
}
Self { s }
}
}
这样我们就可以实现index()
像这样:
fn index() -> StringlyResult {
let temp = some_func("pass")
.map_err(|_| "No parameters named pass")?;
try_decrypt_data(&temp).into()
}
(Playground 上的完整代码)
所以是的,Try
特征使用户能够使用?
具有自己类型的运算符。
但是,正如您的示例所示,这是一个糟糕的主意。您可能已经注意到“wat“我上面的代码中的部分。问题是您的 OK 类型已经耗尽了整个类型(该类型的所有实例都是有效的 OK 实例)。
考虑一个函数get_file_size() -> u64
。现在这个函数可能会失败(即它无法确定文件大小)。你不能就这么回来0
发出发生故障的信号。函数的调用者如何区分函数无法确定文件大小的环境和文件实际上为 0 字节大的环境?
同样,函数的调用者如何区分发生错误的情况和解密后的文本是字面意思的情况"No parameters named pass"
?打电话的人不能!这很糟糕。
请注意,有一些类似的东西,虽然没有那么糟糕,但在 Rust 中仍然不是很惯用:get_file_size() -> i64
。在这里,我们could return -1
发出失败信号。这还好,因为-1
永远不可能是有效的文件大小! (换句话说,并非您的类型的所有实例都是有效的 OK 实例)。然而,在这种情况下,仍然很容易忘记检查错误。这就是为什么在 Rust 中,我们总是想使用Result
.
为了使错误处理更容易,请考虑使用板条箱failure。这样,您就可以轻松地使用字符串作为错误消息,而无需牺牲程序的类型安全性或健全性。例子:
use failure::{Error, ResultExt};
fn index() -> Result<String, Error> {
let temp = some_func("pass")
.context("No parameters named pass")?;
Ok(try_decrypt_data(&temp)?)
}