Warp 过滤器将变量移出其环境
Warp filter moving variable out of its environment
我正在尝试实现一个过滤器,它位于我的所有路由中并提取 header 并将可能的令牌与我系统中存储的内容相匹配。
我想实现类似 the warp rejection example 的功能,但出现错误
expected a closure that implements the Fn
trait, but this closure
only implements FnOnce
closure is FnOnce
because it moves the
variable tmp
out of its environment
我有点明白编译器在说什么,但不知道如何解决。
我以为 let tmp = store.clone()
会。
我有过滤器:
pub fn haystack_auth_header(store: Store) -> impl Filter<Extract = (Store,), Error = Rejection> + Clone {
let tmp = store.clone();
warp::header("Authorization").and_then (|auth_header: String| async move {
// Authorization: BEARER authToken=xxxyyyzzz
let result = auth_token(&auth_header); //-> IResult<&'a str, (&'a str, &'a str), (&'a str, ErrorKind)> {
if result.is_err() {
return Err(reject::custom(HayStackAuthToken));
}
let (_, key_value) = result.unwrap();
let auth_token_result = tmp.read().get_authtoken();
if auth_token_result.is_err() {
return Err(reject::custom(HayStackAuthToken));
}
let auth_token_option = auth_token_result.unwrap();
if auth_token_option.is_none() {
return Err(reject::custom(HayStackAuthToken));
}
let auth_token = auth_token_option.unwrap();
if auth_token != key_value.1 {
return Err(reject::custom(HayStackAuthToken));
}
Ok(tmp)
})
}
store
是 type Store = Arc<RwLock<Box<dyn UserAuthStore>>>
,UserAuthStore
是 trait UserAuthStore: fmt::Debug + Send + Sync
。
UserAuthStore 定义为
pub trait UserAuthStore: fmt::Debug + Send + Sync {
// Return handshake token for username. If user has no handshake token generate one
fn get_handshake_token(&self, username: &str) -> HaystackResult<String>;
fn get_username(&self, handshake_token: &str) -> HaystackResult<String>;
fn set_temporary_value(&mut self, k: &str, v: &str) -> HaystackResult<()>;
fn get_temporary_value(&self, k: &str) -> HaystackResult<Option<&String>>;
fn set_authtoken(&mut self, s: String) -> HaystackResult<()>;
/// returns a base64 encoded sha256 salt of password.
fn get_password_salt(&self) -> HaystackResult<String>;
fn get_salted_password(&self) -> HaystackResult<String>;
fn get_authtoken(&self) -> HaystackResult<Option<String>>;
}
为什么 clone
在这里不起作用?
完整的错误是
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> src/server/mod.rs:997:45
|
997 | warp::header("Authorization").and_then (|auth_header: String| async move {
| ___________________________________--------__^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_-
| | | |
| | | this closure implements `FnOnce`, not `Fn`
| | the requirement to implement `Fn` derives from here
998 | |
999 | | // Authorization: BEARER authToken=xxxyyyzzz
1000 | | let result = auth_token(&auth_header); //-> IResult<&'a str, (&'a str, &'a str), (&'a str, ErrorKind)> {
... |
1026 | | Ok(tmp.clone())
1027 | | })
| |_____- closure is `FnOnce` because it moves the variable `tmp` out of its environment
这个问题表明您还没有明确区分 fn
层次结构:
摘自 here.
Warp 的过滤函数需要实现 Fn 特性。
这意味着您无法访问外部上下文(读取:环境)。
第一次 AndThen 调用您的闭包时,该函数将使用“唯一”可用的 tmp 变量,因此它将无法用于以后的调用。由于闭包它获得了其上下文的所有权,这意味着它正在实现 FnOnce。
正如@msrd0 在评论中所建议的那样,这可能可以通过在函数中移动该调用来解决,但我需要一个 MRE 来确定它。
在创建了一个简单的测试用例之后,我设法通过以下函数让它运行。
pub fn haystack_auth_header(store: Store) -> impl Filter<Extract = (Store,), Error = Rejection> + Clone {
warp::header("Authorization").and_then (
move |auth_header: String|
{
let tmp = store.clone();
async move {
let tmp = tmp.clone();
if tmp.read().get_authtoken().is_none() {
return Err(reject::custom(HayStackAuthToken));
}
Ok(tmp.clone())
}
}
)
}
所以最后只需要在正确的地方克隆。
我正在尝试实现一个过滤器,它位于我的所有路由中并提取 header 并将可能的令牌与我系统中存储的内容相匹配。
我想实现类似 the warp rejection example 的功能,但出现错误
expected a closure that implements the
Fn
trait, but this closure only implementsFnOnce
closure isFnOnce
because it moves the variabletmp
out of its environment
我有点明白编译器在说什么,但不知道如何解决。
我以为 let tmp = store.clone()
会。
我有过滤器:
pub fn haystack_auth_header(store: Store) -> impl Filter<Extract = (Store,), Error = Rejection> + Clone {
let tmp = store.clone();
warp::header("Authorization").and_then (|auth_header: String| async move {
// Authorization: BEARER authToken=xxxyyyzzz
let result = auth_token(&auth_header); //-> IResult<&'a str, (&'a str, &'a str), (&'a str, ErrorKind)> {
if result.is_err() {
return Err(reject::custom(HayStackAuthToken));
}
let (_, key_value) = result.unwrap();
let auth_token_result = tmp.read().get_authtoken();
if auth_token_result.is_err() {
return Err(reject::custom(HayStackAuthToken));
}
let auth_token_option = auth_token_result.unwrap();
if auth_token_option.is_none() {
return Err(reject::custom(HayStackAuthToken));
}
let auth_token = auth_token_option.unwrap();
if auth_token != key_value.1 {
return Err(reject::custom(HayStackAuthToken));
}
Ok(tmp)
})
}
store
是 type Store = Arc<RwLock<Box<dyn UserAuthStore>>>
,UserAuthStore
是 trait UserAuthStore: fmt::Debug + Send + Sync
。
UserAuthStore 定义为
pub trait UserAuthStore: fmt::Debug + Send + Sync {
// Return handshake token for username. If user has no handshake token generate one
fn get_handshake_token(&self, username: &str) -> HaystackResult<String>;
fn get_username(&self, handshake_token: &str) -> HaystackResult<String>;
fn set_temporary_value(&mut self, k: &str, v: &str) -> HaystackResult<()>;
fn get_temporary_value(&self, k: &str) -> HaystackResult<Option<&String>>;
fn set_authtoken(&mut self, s: String) -> HaystackResult<()>;
/// returns a base64 encoded sha256 salt of password.
fn get_password_salt(&self) -> HaystackResult<String>;
fn get_salted_password(&self) -> HaystackResult<String>;
fn get_authtoken(&self) -> HaystackResult<Option<String>>;
}
为什么 clone
在这里不起作用?
完整的错误是
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> src/server/mod.rs:997:45
|
997 | warp::header("Authorization").and_then (|auth_header: String| async move {
| ___________________________________--------__^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_-
| | | |
| | | this closure implements `FnOnce`, not `Fn`
| | the requirement to implement `Fn` derives from here
998 | |
999 | | // Authorization: BEARER authToken=xxxyyyzzz
1000 | | let result = auth_token(&auth_header); //-> IResult<&'a str, (&'a str, &'a str), (&'a str, ErrorKind)> {
... |
1026 | | Ok(tmp.clone())
1027 | | })
| |_____- closure is `FnOnce` because it moves the variable `tmp` out of its environment
这个问题表明您还没有明确区分 fn
层次结构:
Warp 的过滤函数需要实现 Fn 特性。 这意味着您无法访问外部上下文(读取:环境)。
第一次 AndThen 调用您的闭包时,该函数将使用“唯一”可用的 tmp 变量,因此它将无法用于以后的调用。由于闭包它获得了其上下文的所有权,这意味着它正在实现 FnOnce。
正如@msrd0 在评论中所建议的那样,这可能可以通过在函数中移动该调用来解决,但我需要一个 MRE 来确定它。
在创建了一个简单的测试用例之后,我设法通过以下函数让它运行。
pub fn haystack_auth_header(store: Store) -> impl Filter<Extract = (Store,), Error = Rejection> + Clone {
warp::header("Authorization").and_then (
move |auth_header: String|
{
let tmp = store.clone();
async move {
let tmp = tmp.clone();
if tmp.read().get_authtoken().is_none() {
return Err(reject::custom(HayStackAuthToken));
}
Ok(tmp.clone())
}
}
)
}
所以最后只需要在正确的地方克隆。