Rust 函数签名和寿命
Rust function signatures and outliving
为了学习 Rust,我正在编写一个解析器组合器库。现在我遇到了一个涉及复杂切片类型和所有权的问题。我有一些构建块功能,我希望能够单独使用:
pub fn achar(character: char) -> impl Fn(&str) -> Option<char> {
move |input| match input.chars().next() {
Some(c) if c == character => Some(c),
_ => None,
}
}
pub fn alternatives<'a, T>(
alts: &'a [impl Fn(&'a str) -> Option<T>],
) -> impl Fn(&'a str) -> Option<T> {
move |input| {
for alt in alts.iter() {
let tried = alt(input);
if tried.is_none() {
continue;
}
return tried;
}
None
}
}
pub fn one_of<'a>(allowed: &'a str) -> impl Fn(&'a str) -> Option<char> {
let v = allowed.chars().map(achar).collect::<Vec<_>>();
alternatives(&v)
}
用法将如下所示:
fn main() {
println!("{:?}", achar('f')("foo"));
println!("{:?}", alternatives(vec![achar('f'), achar('b')])("foo"));
println!("{:?}", one_of("foo")("foo"));
}
像这样我得到以下错误:
= note: expected type `for<'r> fn(&'r str) -> std::option::Option<char> {any_char}`
found reference `&impl for<'r> std::ops::Fn<(&'r str,)>`
我会说 quote
实现了 Fn(&str)
,不是吗?我怎样才能让它工作?
一旦解决了下一个问题:
33 |备选方案(&v)
| ^^^^^^^^^^^^^^--^
| | |
| | `v` 在这里借用
| returns 引用当前函数拥有的数据的值
当然,内联并不能解决问题。我不知道怎么攻击它。
这里发生了很多事情:
pub fn alternatives<'a, T>(
alts: &'a [impl Fn(&'a str) -> Option<T>],
) -> impl Fn(&'a str) -> Option<T> {
move |input| {
...
}
}
上面说alternatives
要求切片alts
中的所有元素都是同一类型,并且这个类型实现了Fn(&'a str) -> Option<T>
。但是,在调用 let escaping = alternatives(&vec![any_char, "e, &backslash]);
(或者甚至只是 vec![any_char, "e, &backslash];
)时,元素具有不同的类型(一个是 any_char
类型,下一个是 quote
类型,等等).另一方面,vec![achar('f'), achar('b')]
有效,因为所有元素都具有 achar
类型。
也就是说,即使所有元素都实现了Fn(&str)->Option
,它们也不是完全相同的类型。
关于下一个错误:
pub fn one_of<'a>(allowed: &'a str) -> impl Fn(&'a str) -> Option<char> {
let v = allowed.chars().map(achar).collect::<Vec<_>>();
alternatives(&v)
}
这里,你returnalternatives(&v)
借v
。但是 v
在 one_of
的末尾超出范围,这意味着 alternatives
的结果将引用已被破坏的东西,因此 rust 不允许这样做。
现在,对于 alternatives
接受的类型,我们可以做什么?
alternatives
可以接受盒装函数。然而,这会产生一些运行时开销,但会允许备选方案的数量在运行时是动态的。
alternatives
可以接受函数指针。但是,这将禁止(环境捕获)闭包。
alternatives
可以接受 2 个函数,并且可以通过宏提供两个以上的函数。这基本上会在编译时固定备选方案的数量,但没有运行时开销。
我们如何解决 one_of
中的生命周期问题?
- 这实际上也可以被视为
alternatives
中的一个问题,因为 alternatives
可能应该接受一些函数作为参数并保留它们,以便调用者无需担心生命周期问题。
为了学习 Rust,我正在编写一个解析器组合器库。现在我遇到了一个涉及复杂切片类型和所有权的问题。我有一些构建块功能,我希望能够单独使用:
pub fn achar(character: char) -> impl Fn(&str) -> Option<char> {
move |input| match input.chars().next() {
Some(c) if c == character => Some(c),
_ => None,
}
}
pub fn alternatives<'a, T>(
alts: &'a [impl Fn(&'a str) -> Option<T>],
) -> impl Fn(&'a str) -> Option<T> {
move |input| {
for alt in alts.iter() {
let tried = alt(input);
if tried.is_none() {
continue;
}
return tried;
}
None
}
}
pub fn one_of<'a>(allowed: &'a str) -> impl Fn(&'a str) -> Option<char> {
let v = allowed.chars().map(achar).collect::<Vec<_>>();
alternatives(&v)
}
用法将如下所示:
fn main() {
println!("{:?}", achar('f')("foo"));
println!("{:?}", alternatives(vec![achar('f'), achar('b')])("foo"));
println!("{:?}", one_of("foo")("foo"));
}
像这样我得到以下错误:
= note: expected type `for<'r> fn(&'r str) -> std::option::Option<char> {any_char}`
found reference `&impl for<'r> std::ops::Fn<(&'r str,)>`
我会说 quote
实现了 Fn(&str)
,不是吗?我怎样才能让它工作?
一旦解决了下一个问题:
33 |备选方案(&v) | ^^^^^^^^^^^^^^--^ | | | | | `v` 在这里借用 | returns 引用当前函数拥有的数据的值
当然,内联并不能解决问题。我不知道怎么攻击它。
这里发生了很多事情:
pub fn alternatives<'a, T>(
alts: &'a [impl Fn(&'a str) -> Option<T>],
) -> impl Fn(&'a str) -> Option<T> {
move |input| {
...
}
}
上面说alternatives
要求切片alts
中的所有元素都是同一类型,并且这个类型实现了Fn(&'a str) -> Option<T>
。但是,在调用 let escaping = alternatives(&vec![any_char, "e, &backslash]);
(或者甚至只是 vec![any_char, "e, &backslash];
)时,元素具有不同的类型(一个是 any_char
类型,下一个是 quote
类型,等等).另一方面,vec![achar('f'), achar('b')]
有效,因为所有元素都具有 achar
类型。
也就是说,即使所有元素都实现了Fn(&str)->Option
,它们也不是完全相同的类型。
关于下一个错误:
pub fn one_of<'a>(allowed: &'a str) -> impl Fn(&'a str) -> Option<char> {
let v = allowed.chars().map(achar).collect::<Vec<_>>();
alternatives(&v)
}
这里,你returnalternatives(&v)
借v
。但是 v
在 one_of
的末尾超出范围,这意味着 alternatives
的结果将引用已被破坏的东西,因此 rust 不允许这样做。
现在,对于 alternatives
接受的类型,我们可以做什么?
alternatives
可以接受盒装函数。然而,这会产生一些运行时开销,但会允许备选方案的数量在运行时是动态的。alternatives
可以接受函数指针。但是,这将禁止(环境捕获)闭包。alternatives
可以接受 2 个函数,并且可以通过宏提供两个以上的函数。这基本上会在编译时固定备选方案的数量,但没有运行时开销。
我们如何解决 one_of
中的生命周期问题?
- 这实际上也可以被视为
alternatives
中的一个问题,因为alternatives
可能应该接受一些函数作为参数并保留它们,以便调用者无需担心生命周期问题。