Whats with as_string()?


Having spent a bit of time with Rust, I’ve gotten used to doing the translation between a String and a &str through using:

let foo = String::from_str("foo");

Which felt verbose, and wound up everywhere. After going through and cleaning up the latest round of warnings, all those have been replaced with:

let foo = String::from_str("foo");

Which is certainly more terse. :smile: However, we’ve really just pushed food around the plate, and in some cases, made things look truly odd:

    for line in push_error.lines_any() {
        debug!("error: {}", line);
        if line.starts_with("remote") {
            let r = regex!(r"remote: (.+)");
            let caps_result = r.captures(line);
            match caps_result {
                Some(caps) => { sayln("white", &format!("{}", caps.at(1).unwrap())[]); },
                None => {}

Check out the call to format! above. I’m pretty sure I could clean it up by making sayln generic, which I can do, but it really feels like we should be able to cast the String to an &str on demand. Is that the plan?


In the latest nightly you should be able to convert a String to a &str just by using &:

sayln("white", &format!("{}", ...));

Sometimes it is not possible due to generics, but you could still invoke the dereference directly:

sayln("white", &*format!("{}", ...));

And the foo[] syntax is also going to be removed.


That’s redundant. You’re creating a String (foo) from an &str, dereferencing foo (the String) into a str (dereferenced &str), and then creating a new String with .as_string().

let foo = String::from_str("foo");

Here, you’re going from &str “foo” to String “foo” back to &str “foo”. Furthermore, some_function's signature must be different because it’s taking an &str not a String like the first case.


Yeah, I know it’s redundant - it was a, perhaps bad, example. :wink:


as_string is an alternate solution to the “hashtable string key String vs &str equivalence problem”. It’s kind of redundant now, but it’s only purpose is to be able to create a &String temporary from a &str without allocating anything.

Unfortunately the example in the documentation doesn’t make any sense (because its true use case doesn’t exist if you plan ahead).


By that, do you mean "replaced with foo[..]"?


No, &foo. This is called ‘deref conversions’



And it will in fact be replaced by &foo[..], as &foo is not a perfect replacement for &foo[].

Consider the following code:

fn do_stuff_generic<T>(data: T) {}
fn do_stuff_slice(data: &[u32]) {}

fn main() {
  let foo = vec![1, 2, 3];
  do_stuff_generic(&foo); // passes in &Vec<T> because it is allowed
  do_stuff_generic(&foo[..]); // passes in &[T]
  do_stuff_slice(&foo); // passes in &[T] because of Deref Coercions
  do_stuff_slice(&foo[..]); // passes in &[T]


Both of these pass in &[T], correct?


Neither of those should compile since foo[..] has type [T] which is unsized. You need the & to get a fat pointer to what is otherwise an rvalue.

foo[..] is basically alternate syntax for *foo


So the slicing operator does not return a slice, but an array? That’s surprising, but I get why it’s done that way.


It’s not an array. See A contiguous storage by any other name for all the varieties.