【发布时间】:2020-05-06 05:15:36
【问题描述】:
原始问题
这段代码与我试图修复的那段代码比较相似。我也在Rust user's forum 上问过这个问题。
/// assume this function can't be modified.
fn foo<A>(
f1: impl Fn(&str) -> Result<(&str, A), ()>,
base: &str,
f2: impl Fn(A) -> bool
) {
let s: String = base.to_owned();
let option = Some(s.as_ref());
let mapped = option.map(f1);
let r = mapped.unwrap();
let (rem, prod) = r.unwrap();
assert!(f2(prod));
assert_eq!(rem.len(), 0);
}
fn main() {
fn bar<'a>(s: &'a str) -> Result<(&'a str, &'a str), ()> {
Ok((&s[..1], &s[..]))
}
fn baz(s: &str) -> Result<(&str, &str), ()> {
Ok((&s[..1], &s[..]))
}
foo(bar, "string", |s| s.len() == 5); // fails to compile
foo(baz, "string", |s| s.len() == 5); // fails to compile
}
error[E0271]: type mismatch resolving `for<'r> <for<'a> fn(&'a str) -> std::result::Result<(&'a str, &'a str), ()> {main::bar} as std::ops::FnOnce<(&'r str,)>>::Output == std::result::Result<(&'r str, _), ()>`
--> src/main.rs:27:5
|
2 | fn foo<A>(
| ---
3 | f1: impl Fn(&str) -> Result<(&str, A), ()>,
| --------------------- required by this bound in `foo`
...
27 | foo(bar, "string", |s| s.len() == 5); // fails to compile
| ^^^ expected bound lifetime parameter, found concrete lifetime
编辑:
根据这里的许多人、internals thread I made 和 rust 用户论坛上的建议,我更改了我的代码以通过使用包装器特征来简化它。
trait Parser<'s> {
type Output;
fn call(&self, input: &'s str) -> (&'s str, Self::Output);
}
impl<'s, F, T> Parser<'s> for F
where F: Fn(&'s str) -> (&'s str, T) {
type Output = T;
fn call(&self, input: &'s str) -> (&'s str, T) {
self(input)
}
}
fn foo<F1, F2>(
f1: F1,
base: &'static str,
f2: F2
)
where
F1: for<'a> Parser<'a>,
F2: FnOnce(&<F1 as Parser>::Output) -> bool
{
// These two lines cannot be changed.
let s: String = base.to_owned();
let str_ref = s.as_ref();
let (remaining, produced) = f1.call(str_ref);
assert!(f2(&produced));
assert_eq!(remaining.len(), 0);
}
struct Wrapper<'a>(&'a str);
fn main() {
fn bar<'a>(s: &'a str) -> (&'a str, &'a str) {
(&s[..1], &s[..])
}
fn baz<'a>(s: &'a str) -> (&'a str, Wrapper<'a>) {
(&s[..1], Wrapper(&s[..]))
}
foo(bar, "string", |s| s.len() == 5); // fails to compile
foo(baz, "string", |s| s.0.len() == 5); // fails to compile
}
此代码当前生成内部编译器错误:
error: internal compiler error: src/librustc_infer/traits/codegen/mod.rs:61: Encountered error `OutputTypeParameterMismatch(Binder(<[closure@src/main.rs:45:24: 45:40] as std::ops::FnOnce<(&<for<'a> fn(&'a str) -> (&'a str, &'a str) {main::bar} as Parser<'_>>::Output,)>>), Binder(<[closure@src/main.rs:45:24: 45:40] as std::ops::FnOnce<(&&str,)>>), Sorts(ExpectedFound { expected: &str, found: <for<'a> fn(&'a str) -> (&'a str, &'a str) {main::bar} as Parser<'_>>::Output }))` selecting `Binder(<[closure@src/main.rs:45:24: 45:40] as std::ops::FnOnce<(&&str,)>>)` during codegen
thread 'rustc' panicked at 'Box<Any>', src/librustc_errors/lib.rs:875:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports
note: rustc 1.43.0 (4fb7144ed 2020-04-20) running on x86_64-unknown-linux-gnu
note: compiler flags: -C codegen-units=1 -C debuginfo=2 --crate-type bin
note: some of the compiler flags provided by cargo are hidden
error: aborting due to previous error
error: could not compile `playground`.
To learn more, run the command again with --verbose.
我已经提交了错误报告here。
【问题讨论】:
-
您能否更详细地描述预期的行为和问题是什么?很高兴您提供了一个 Playground 链接,但我们不应该运行 Playground 来猜测您在问什么。
-
Fntrait 似乎不够灵活,无法表达这一点,因此您应该定义自己的 trait。 -
我刚刚在操场上看到了“假设这个函数不能被修改”的评论。在这种情况下,该函数根本无法获取您想要传入的函数。
A需要具有静态生命周期,因此使其成为某种“拥有”类型(在本例中为String)。跨度> -
@PeterHall 好的,那么假设可以修改该功能,您会进行哪些修改?
-
@AntoniaCalia-Bogan 我在下面的回答中有一个建议。但是我们在这里讨论的是泛型函数,因此它实际上取决于您对泛型的预期界限。
标签: generics rust lifetime borrowing