0

So I just started learning about Rust and the Implicit Deref Coercion. A "problem" I now often tumble over, is that this automatic deref does not work inside of other types, e.g. as Item types of collections. In the following example (sandbox), what changes can be done in the function signature, to make the last line in main work, or is there no other way than do the conversion outside of the function call explicitly?

fn find_in_vec<T>(v: Vec<T>) -> bool
where
    T: AsRef<str>
{
    for e in v {
        if e.as_ref() == "hello" {
            return true;
        }
    }
    false
}

fn is_hello(s: &str) -> bool {
    s == "hello"
}

fn main() {
    let h1: &str = "hello";
    let h2: &String = &"hi".to_string();
    let h3: &Box<String> = &Box::new("hi".to_string());
    println!("{}", is_hello(h1));  // works
    println!("{}", is_hello(h2));  // works
    println!("{}", is_hello(h3));  // works

    let a: Vec<&str> = vec!["hello", "world", "!"];
    let b: Vec<&str> = vec!["hallo", "world", "!"];
    let chelp = "hello".to_string();
    let c: Vec<&String> = vec![&chelp];
    let d: Vec<&Box<String>> = vec![&Box::new("hello".to_string())];
    println!("{}", find_in_vec(a));  // works
    println!("{}", find_in_vec(b));  // works
    println!("{}", find_in_vec(c));  // works
    println!("{}", find_in_vec(d));  // fails
}

Compile Error:

error[E0277]: the trait bound `Box<String>: AsRef<str>` is not satisfied
  --> src/main.rs:33:32
   |
33 |     println!("{}", find_in_vec(d));
   |                    ----------- ^ the trait `AsRef<str>` is not implemented for `Box<String>`
   |                    |
   |                    required by a bound introduced by this call
   |
   = help: the trait `AsRef<T>` is implemented for `Box<T, A>`
   = note: required for `&Box<String>` to implement `AsRef<str>`
note: required by a bound in `find_in_vec`

Any insights on idiomatic ways to solve/work around/avoid this problem would be greatly appreciated!

Note: I know that the Box<String> is overkill in this example, just consider it a minimal example. In my "real" world, I don't have boxed Strings but a list of pointers to different structs all having the same Trait, e.g. Box<dyn MyTrait>.

David S.
  • 303
  • 2
  • 10
  • `Box` is kind of a nonsense type. `String` is already heap-allocated, so why box it? – PitaJ Sep 01 '23 at 15:03
  • As pointed out, you are better off getting rid of those `Box`, as they are inefficient and may bring more difficulties integrating with generic code. – E_net4 Sep 01 '23 at 15:08
  • Thanks for your fast responses. The Box was a deliberate example, as I already experimented with `AsRef` but did not fully grasp it yet, so I did not include it in my first post. I modified the example now, considering the duplicate-linked questions, using AsRef, showing that it actually works with a plain `String`. However, because the `Box` needs to chain 2 derefs, which in automatic deref coercion works, however, it still does not work in this case. Please reconsider my question as open. – David S. Sep 01 '23 at 20:26
  • @E_net4 could you help me reopen this question or give further clarifications regarding my comment and edit of the question, why you still might think it is a duplicate? If the issue is really the Box in `Box` is there something better I can use in generic functions? – David S. Sep 01 '23 at 21:33
  • Do the values inside the `Box` also implement `AsRef`? In that case, you may be able to extend or create a new trait to include both requirements in your trait object (https://stackoverflow.com/q/28897297), so that it provides the behaviour of both `MyTrait` and `AsRef`. Please see if this works. – E_net4 Sep 01 '23 at 22:15

0 Answers0