我有一些代码看起来像这样(大大简化的版本)。函数接受两个类型为LoadClientand的函数参数CheckApproval,并返回错误或字符串。
pub struct Client {
pub id: String,
}
pub enum MyErr {
RequiresApproval(Client, String),
LoadFailed,
}
pub fn authorize<LoadClient, CheckApproval>(load_client: LoadClient, check_approval: CheckApproval) -> Result<String, MyErr>
where
LoadClient: FnOnce(String) -> Result<Client, String>,
CheckApproval: for<'a> FnOnce(&'a Client, &str) -> Result<&'a str, ()>,
{
let client = load_client("hello".to_string()).map_err(|_| MyErr::LoadFailed)?;
let permission = "something";
// This doesn't compile
// let authorized = check_approval(&client, permission).map_err(|_| MyErr::RequiresApproval(client, permission.to_string()))?;
// Ok(authorized.to_string())
// This version does
match check_approval(&client, permission) {
Err(_) => Err(MyErr::RequiresApproval(client, permission.to_string())),
Ok(authorized) => Ok(authorized.to_string()),
}
}
Run Code Online (Sandbox Code Playgroud)
我想?与check_approval调用一起使用(如注释掉的代码所示)以获得更简单的代码并避免额外的嵌套 -Ok最终匹配中的分支实际上是一个更长的块。
不幸的是,这不能编译:
error[E0505]: cannot move out of `client` because it is borrowed
--> src/lib.rs:19:66
|
19 | let authorized = check_approval(&client, permission).map_err(|_| MyErr::RequiresApproval(client, permission.to_string()))?;
| ------- ------- ^^^ ------ move occurs due to use in closure
| | | |
| | | move out of `client` occurs here
| | borrow later used by call
| borrow of `client` occurs here
Run Code Online (Sandbox Code Playgroud)
这些看起来很相似(在我未经训练的眼睛看来)。client到时候归还的借用引用不是被map_err调用了吗?
我的主要问题:有没有办法解决这个问题并在不使用的情况下编写代码match?
虽然代码的两个版本在语义上是等效的,但对于编译器来说它们实际上是完全不同的。
失败的调用Result::map_err()使用一个捕获 的值的闭包client。也就是说,client被移入闭包,但在调用 时被借用check_approval()。错误就在这里,借用的值无法移动。
您可能认为该借用应该在函数返回时完成,但事实并非如此Result<&'a str, ()>,因为它的返回类型'a恰好是该借用的生命周期。client只要存在,借用就会延长'a。这就是你的第二个版本起作用的原因:当你匹配你的 时Result,'a不会扩展到Err(())分支,只扩展到Ok(&'a str),因此Err(())能够client自由移动。
有没有办法解决这个问题并在不使用的情况下编写代码
match?
好吧,您正在调用authorized.to_string()返回&'a str并将其转换为拥有的String. 因此,如果您可以将CheckApproval约束更改为:
CheckApproval: FnOnce(&Client, &str) -> Result<String, ()>,
Run Code Online (Sandbox Code Playgroud)
问题就消失了。
to_string()如果你无法改变这一点,另一种选择是在将 the 移入闭包之前执行此操作client,在借用造成损害之前完成借用:
let authorized = check_approval(&client, permission)
.map(|a| a.to_string())
.map_err(|_| MyErr::RequiresApproval(client, permission.to_string()))?;
Ok(authorized)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11363 次 |
| 最近记录: |