从与就地定义不一致的函数返回闭包
Returning closure from function inconsitent with defining in place
在尝试使用 actix-web 实现一个简单的 Web 服务器应用程序时,我遇到了 Rust 闭包明显不一致的行为,我不知道如何解释。
我有以下代码:
use actix_web::{web, App, HttpServer};
#[derive(Clone)]
struct Config {
val1: String,
val2: String,
val3: String,
}
fn main() {
let conf = Config {
val1: "just".to_string(),
val2: "some".to_string(),
val3: "data".to_string(),
};
HttpServer::new(move ||
App::new().configure(create_config(&conf))
)
.bind("127.0.0.1:8088")
.unwrap()
.run()
.unwrap();
}
fn create_config<'a>(conf: &'a Config) -> impl FnOnce(&mut web::ServiceConfig) + 'a {
move |app: &mut web::ServiceConfig| {
// Have to clone config because web::get().to by definition requires
// its argument to have static lifetime, which is longer than 'a
let my_own_conf_clone = conf.clone();
app.service(
web::scope("/user")
.route("", web::get().to(move || get_user(&my_own_conf_clone)))
);
}
}
fn get_user(conf: &Config) -> String {
println!("Config {} is {} here!", conf.val3, conf.val1);
"User McUser".to_string()
}
此代码有效。注意我传递给 web::get().to
的闭包。我用它将 Config
对象向下传递给 get_user
并且仍然根据需要使用没有参数的函数呈现 web::get().to
。此时我决定将闭包生成移动到一个单独的函数中:
fn create_config<'a>(conf: &'a Config) -> impl FnOnce(&mut web::ServiceConfig) + 'a {
move |app: &mut web::ServiceConfig| {
app.service(
web::scope("/user")
.route("", web::get().to(gen_get_user(conf)))
);
}
}
fn gen_get_user(conf: &Config) -> impl Fn() -> String {
let my_own_conf_clone = conf.clone();
move || get_user(&my_own_conf_clone)
}
fn get_user(conf: &Config) -> String {
println!("Config {} is {} here!", conf.val3, conf.val1);
"User McUser".to_string()
}
此代码编译失败,出现以下错误:
error[E0277]: the trait bound `impl std::ops::Fn<()>: actix_web::handler::Factory<_, _>` is not satisfied
--> src/main.rs:30:39
|
30 | .route("", web::get().to(gen_get_user(conf)))
| ^^ the trait `actix_web::handler::Factory<_, _>` is not implemented for `impl std::ops::Fn<()>`
为什么第二种情况失败而第一种情况不失败?为什么特征 Factory
在第一种情况下得到满足,但在第二种情况下却没有?可能是工厂(来源是here)的错? return 闭包是否有不同的方法,在这种情况下可行?您可以建议任何其他方法吗? (注意 Factory
不是 public 所以我不能自己直接实现)
如果你想玩弄代码,我这里有:https://github.com/yanivmo/rust-closure-experiments
请注意,您可以在提交之间移动以查看处于工作状态或失败状态的代码。
然后使用 impl Trait
作为 return 输入除该值实现之外的所有其他类型信息 Trait
被删除。
在这种特殊情况下,闭包 move || get_user(&my_own_conf_clone)
实现了 Fn() -> String
和 Clone
,但在 returning Clone
之后被删除。
但是由于 Factory
为 Fn() -> String + Clone
实现,而不是 Fn() -> String
return 值不再实现工厂。
这可以通过将 gen_get_user
更改为
来解决
fn gen_get_user(conf: &Config) -> impl Fn() -> String + Clone{
let my_own_conf_clone = conf.clone();
move || get_user(&my_own_conf_clone)
}
在尝试使用 actix-web 实现一个简单的 Web 服务器应用程序时,我遇到了 Rust 闭包明显不一致的行为,我不知道如何解释。
我有以下代码:
use actix_web::{web, App, HttpServer};
#[derive(Clone)]
struct Config {
val1: String,
val2: String,
val3: String,
}
fn main() {
let conf = Config {
val1: "just".to_string(),
val2: "some".to_string(),
val3: "data".to_string(),
};
HttpServer::new(move ||
App::new().configure(create_config(&conf))
)
.bind("127.0.0.1:8088")
.unwrap()
.run()
.unwrap();
}
fn create_config<'a>(conf: &'a Config) -> impl FnOnce(&mut web::ServiceConfig) + 'a {
move |app: &mut web::ServiceConfig| {
// Have to clone config because web::get().to by definition requires
// its argument to have static lifetime, which is longer than 'a
let my_own_conf_clone = conf.clone();
app.service(
web::scope("/user")
.route("", web::get().to(move || get_user(&my_own_conf_clone)))
);
}
}
fn get_user(conf: &Config) -> String {
println!("Config {} is {} here!", conf.val3, conf.val1);
"User McUser".to_string()
}
此代码有效。注意我传递给 web::get().to
的闭包。我用它将 Config
对象向下传递给 get_user
并且仍然根据需要使用没有参数的函数呈现 web::get().to
。此时我决定将闭包生成移动到一个单独的函数中:
fn create_config<'a>(conf: &'a Config) -> impl FnOnce(&mut web::ServiceConfig) + 'a {
move |app: &mut web::ServiceConfig| {
app.service(
web::scope("/user")
.route("", web::get().to(gen_get_user(conf)))
);
}
}
fn gen_get_user(conf: &Config) -> impl Fn() -> String {
let my_own_conf_clone = conf.clone();
move || get_user(&my_own_conf_clone)
}
fn get_user(conf: &Config) -> String {
println!("Config {} is {} here!", conf.val3, conf.val1);
"User McUser".to_string()
}
此代码编译失败,出现以下错误:
error[E0277]: the trait bound `impl std::ops::Fn<()>: actix_web::handler::Factory<_, _>` is not satisfied
--> src/main.rs:30:39
|
30 | .route("", web::get().to(gen_get_user(conf)))
| ^^ the trait `actix_web::handler::Factory<_, _>` is not implemented for `impl std::ops::Fn<()>`
为什么第二种情况失败而第一种情况不失败?为什么特征 Factory
在第一种情况下得到满足,但在第二种情况下却没有?可能是工厂(来源是here)的错? return 闭包是否有不同的方法,在这种情况下可行?您可以建议任何其他方法吗? (注意 Factory
不是 public 所以我不能自己直接实现)
如果你想玩弄代码,我这里有:https://github.com/yanivmo/rust-closure-experiments 请注意,您可以在提交之间移动以查看处于工作状态或失败状态的代码。
然后使用 impl Trait
作为 return 输入除该值实现之外的所有其他类型信息 Trait
被删除。
在这种特殊情况下,闭包 move || get_user(&my_own_conf_clone)
实现了 Fn() -> String
和 Clone
,但在 returning Clone
之后被删除。
但是由于 Factory
为 Fn() -> String + Clone
实现,而不是 Fn() -> String
return 值不再实现工厂。
这可以通过将 gen_get_user
更改为
fn gen_get_user(conf: &Config) -> impl Fn() -> String + Clone{
let my_own_conf_clone = conf.clone();
move || get_user(&my_own_conf_clone)
}