Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

In Rust, how do I combine two functions that are identical, but one takes &Vec<String> and the other takes &Vec<&String>?

I’ve been doing the Advent of Code to learn Rust, and on day 3 I ended up writing this:

fn ones_per_bit(lines:&Vec<String>, bitcount:usize) -> Vec<u32> {
  let mut out: Vec<u32> = Vec::new();
  out.resize(bitcount, 0);
  for line in lines {
    for (i, c) in line.chars().enumerate() {
      if c == '1' { out[i] += 1; }
    }
  }
  return out;
}

And then copied/pasted it so that I can call it with a &Vec<&String> instead of a &Vec<String>. This worked, but to avoid duplicating the function body, I was hoping to use generics, but my naive implementation looked like this:

fn ones_per_bit<T>(lines:&Vec<T>, bitcount:usize) -> Vec<u32> {
  let mut out: Vec<u32> = Vec::new();
  out.resize(bitcount, 0);
  for line in lines {
    for (i, c) in line.chars().enumerate() {
      if c == '1' { out[i] += 1; }
    }
  }
  return out;
}

Which resulted in:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

error[E0599]: no method named `chars` found for reference `&T` in the current scope
  --> main.rs:44:24
   |
44 |     for (i, c) in line.chars().enumerate() {
   |                        ^^^^^ method not found in `&T`

So I’m missing a concept here. I seem to need to tell rust what types of methods to expect on the generic type, but I’m not sure the best way to do that (or if there’s a better language feature I should be using here).

>Solution :

What you want here is a type that you can dereference as &str.

This is usually done with a <T: AsRef<str>> generic constraint:

fn ones_per_bit<T: AsRef<str>>(lines: &[T], bitcount:usize) -> Vec<u32> {
  let mut out: Vec<u32> = Vec::new();
  out.resize(bitcount, 0);
  for line in lines {
    for (i, c) in line.as_ref().chars().enumerate() {
      if c == '1' { out[i] += 1; }
    }
  }
  return out;
}

Side note: declare the argument as &[T] rather than &Vec[T] so that it works for bot vec references and slices.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading