-
Notifications
You must be signed in to change notification settings - Fork 452
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replacer impl for FnMut impossible lifetime requirements #601
Comments
I don't think this is UB in This is because of the bound So all in all, this is not a bug in regex, rather it is a bug in your usage of Note how both of the following do not compile. use regex::{Regex, Captures};
fn main() {
fn foo<'a>(c: &Captures<'a>) -> &'a str {
c.get(0).unwrap().as_str()
}
fn bar<'a>(c: &'a Captures<'_>) -> &'a str {
c.get(0).unwrap().as_str()
}
let r = Regex::new("aaa").unwrap();
// r.replace_all("aaa", foo); // does not compile,
// r.replace_all("aaa", bar); // does not compile,
} |
I accept that with the current definition I can't use strings from However, I think using strings from If |
This is indeed unfortunate. It seems to me like there ought to be a way to express this, since from my point of view, it is totally safe to write this particular closure. Or at least, I don't understand why it isn't. So this might be one of those rare cases where NLL winds up rejecting what was a previously valid---and still valid---program. But this is not my area of expertise, so I am not super confident here. cc @nikomatsakis Do you have any insight into this issue?
I'm not necessarily opposed to this, but I'm not quite sure how it would work. Certainly, the existing It's worth noting that up until a year ago, the |
I can't think of another implementation that would solve this, and Rust is unlikely to have a feature for this anytime soon, so I'm closing the issue. |
Does anyone have an example of a working (Rust 2018) regex replacement code snippet that avoids the above error, with and without use of variable bindings (Captures)? Thanks (the code fragment of the top-5 Google results are all broken and mostly suffer from the error above)! |
@jochenleidner you need to implement the trait on a struct, not a closure. struct ExampleReplacer;
impl regex::Replacer for ExampleReplacer {
fn replace_append(&mut self, capts: &Captures<'_>, dst: &mut String) {
dst.push_str(some_replacement.unwrap_or_else(|| &capts[0]));
}
} |
Thanks a lot for this rapid reply, that works. BTW, this is the first case where I've seen Rust code that is less readable and considerably more complex than its C++ counterpart:
It may be merited as the Rust solution may buy one more flexibility, but perhaps it's worth adding a "convenience function" implementation like the one you quote above in the Rust std library. |
Code identical to C++ works too — replacer is implemented for strings. The struct/closure alternative is for cases when you want to have something with higher performance or custom replacement logic. |
And in addition to what @kornelski said, simple replacements like you're after are one of the first examples in the crate docs: https://docs.rs/regex/1.4.3/regex/#example-replacement-with-named-capture-groups And there are even more in the docs of the |
Thanks, @kornelski and @BurntSushi - I agree those examples are very useful, and along the lines of what I had in mind. |
Continuing the thread from the forum. Rust gives a warning that this is potentially UB:
In the
Replacer
trait, there's no place to define that the returnedT: AsRef<str>
lives at least as long as'_
inCaptures<'_>
.This becomes more evident if you try to use explicit
&str
as the return type. There's just no way to compile it with'a: 't
or similar requirement:As far as I understand, the difficulty here is that the lifetime in question is inside of function arguments in the trait, but needs to be named outside of it in the closure type. There's just no syntax for such thing.
Ability to return some of the captures for replacement seems quite useful, but having a scary warning for this, and potentially UB or fatal error in the future, is not good.
Is there some clever syntax/generics/lifetimes solution that would make it work?
Can closures be made to work some other way, via wrapper type, or another function call?
Should Rust add some syntax, or make the borrow checker more clever, to make the existing solution acceptable?
The text was updated successfully, but these errors were encountered: