2

The following code tries to check whether a String contains another String. I get a compiler error when I use the String::contains method. I expect String::contains(String) would work straight out of the box.

What is the correct way to do this in Rust, when the pattern being searched for is not a string literal? I did rustc --explain E0277, and it seems like String does not implement the Pattern trait, is that true?

fn main() { let a = String::from("abcdefgh"); let b = String::from("def"); if a.contains(b) { println!("Contained"); } else { println!("Not contained"); } } 

The compiler error:

error[E0277]: the trait bound `std::string::String: std::ops::FnMut<(char,)>` is not satisfied --> src/main.rs:6:10 | 6 | if a.contains(b) { | ^^^^^^^^ the trait `std::ops::FnMut<(char,)>` is not implemented for `std::string::String` | = note: required because of the requirements on the impl of `std::str::pattern::Pattern<'_>` for `std::string::String` 
5
  • Here is a minimal recreation of your issue. And in case you weren't aware, a reference to a string (&foo) can be used anywhere an &str can, so the solution is a trivial s_i.contains(&s_i_minus_1). I'm almost certain this is a duplicate of something, although string contains [rust] search doesn't come up with anything immediately applicable. Commented Jun 3, 2018 at 8:28
  • The example given above is complete and can actually be copied/compiler and run. I do not know what I can remove from the example without making it less than complete. Commented Jun 3, 2018 at 8:31
  • @vamsikal Please take a look at the code BHustus just posted. This is what we would consider a MCVE: it produces the error you are talking about. "Complete" just means that your example contains all the necessary information for the error you are asking about. You can just take BHustus' code and copy it into your question. With a MCVE you'll get those nice upvotes ;-) Commented Jun 3, 2018 at 8:33
  • 1
    "Complete" does not mean your complete project, it means that the code you provide has to be functional (complete) enough to reach the error, without extraneous details that need to be sifted through. That's why "minimal" is the first part of MCVE; your example should be large enough to express the error you're having issue with, and no larger. Commented Jun 3, 2018 at 8:33
  • @vamsikal Thanks for editing your question :) Commented Jun 3, 2018 at 8:51

1 Answer 1

3

Let's check the method signature of str::contains:

pub fn contains<'a, P>(&'a self, pat: P) -> bool where P: Pattern<'a>, 

So the second argument has to be something that implements Pattern, as you already noticed. We can find out who implements that trait by visiting the documentation of Pattern. There we can find these impls:

impl<'a, 'b> Pattern<'a> for &'b str impl<'a> Pattern<'a> for char impl<'a, 'b> Pattern<'a> for &'b [char] impl<'a, F> Pattern<'a> for F where F: FnMut(char) -> bool, impl<'a, 'b, 'c> Pattern<'a> for &'c &'b str impl<'a, 'b> Pattern<'a> for &'b String 

As you can see, the trait isn't directly implemented for String. But it is implemented for &String and &str. And this makes sense: the pattern only needs to be read, so ownership of the String is not needed.

In your example, you wouldn't be able to use b afterwards since it would have been moved into the method:

let a: String = String::from("abcdefgh"); let b: String = String::from("def"); a.contains(b); // If this would work, `b` couldn't be used anymore because it has been moved :( 

So instead of passing String (b), just pass &String (&b):

if a.contains(&b) { ... } // ^ 
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the answer! I went and saw the documentation too, but I could not understand that &'b String, meant a string reference as opposed to just a string. Thanks for clarifying that!
Done! Added the green check mark.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.