0

I am doing multiple replacements at once using the regex crate:

extern crate regex;

use regex::{Captures, Regex};

fn transform(string: &str) {
    let rgx = Regex::new(r"(\n)|(/\w+)").unwrap();
    let res = rgx.replace_all(string, |caps: &Captures| {
        if caps.get(1).is_some() {
            return " ";
        }
        match caps.get(2).map(|m: regex::Match| m.as_str()) {
            Some(z) => return "nope", // how to return formatted z instead?
            None => (),
        }
        unreachable!();
    });
    println!("{}", res);
}

fn main() {
    transform("no errors");
    transform("big\nbad\n/string");
}

Output as expected:

no errors
big bad nope

Instead of "nope", I would like to return z formatted in some way instead. format! doesn't seem like it can be used here due to String / lifetime issues:

match caps.get(2).map(|m: regex::Match| m.as_str()) {
    Some(z) => return format!("cmd: {}", z),
    None => (),
}
error[E0308]: mismatched types
  --> src/main.rs:12:31
   |
12 |             Some(z) => return format!("cmd: {}", z),
   |                               ^^^^^^^^^^^^^^^^^^^^^ expected &str, found struct `std::string::String`
   |
   = note: expected type `&str`
              found type `std::string::String`
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

What should be done instead?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
ruser9575ba6f
  • 258
  • 1
  • 10
  • 1
    `String` doesn't have a lifetime, so it would just work. What errors did you have when you tried? – mcarton Sep 09 '19 at 18:18
  • Please note how I've edited your question to *show* the code you've tried, as well as copying in the *entire error message*. Please take care to provide information in similar ways for all future questions as it's a very effective way to communicate. – Shepmaster Sep 09 '19 at 18:32

1 Answers1

2

Note in the error message:

expected &str

It expects a &str because that's the first type returned by your closure:

return " ";

A closure / function can have only one return type, not two.

The simplest fix is to return a String in both cases:

let res = rgx.replace_all(string, |caps: &Captures| {
    if caps.get(1).is_some() {
        return String::from(" ");
    }
    let m = caps.get(2).unwrap();
    format!("cmd: {}", m.as_str())
});

To be slightly more efficient, you can avoid the String allocation for the space character:

use std::borrow::Cow;
let res = rgx.replace_all(string, |caps: &Captures| {
    if caps.get(1).is_some() {
        return Cow::from(" ");
    }
    let m = caps.get(2).unwrap();
    Cow::from(format!("cmd: {}", m.as_str()))
});

playground

I've also replaced the match with the => () arm paired with the unreachable! with the shorter unwrap.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366