Way for `&str` to automagically become `String` in appropriate situations


#1

In my test code with Rust I’m using a lot of String::from and to_strings on my &str types which I actually want to be String. Is there a compiler plugin or other feature to automatically convert &str types into String?

I’d prefer not to use macros, but are there any other suggestions for avoiding this problem entirely?


#2

No. Rust generally does not do automatic conversions, especially not ones that do big things like, say, allocate on the heap.

They’re effectively the same thing. But even then, a plain old function will do better anyway:

use std::borrow::Cow;

fn S<'a, Str>(s: Str) -> String
where Str: 'a + Into<Cow<'a, str>> {
    /*
    The trip through `Cow` is so that we can take either a
    string slice or an owned `String`, and only do the
    conversion if we absolutely *have* to.
    */
    s.into().into_owned()
}

#[test]
fn test_S() {
    S("test");
    S(String::from("test"));
}

#3

Rust likes to make allocation explicit, which is why it’s this way. Tests are an area where you probably don’t care in this case, though, it’s true.

Any macro or extension would still look like string!(“foo”) though, so something less than a .to_string() unlikely to be available. I’m not sure such a thing is possible.


#4

Huh? <String as Into<String>>::into is just the identity function, so it wouldn’t allocate. Going through Cow just introduces an unnecessary branch (which will hopefully be pruned) into an otherwise static operation.


#5

True, but that allows things like Vec<u8> to be passed, and that felt semantically weird.


#6

Given the purposes and target of Rust, it’s normal for heap allocations to be always explicit. But “explicit” doesn’t need to equal “long to write”.

A syntax like "foo"s (with a trailing “s”) to create a heap-allocated string is fully explicit, but it’s also short and more handy.

I don’t know if this is a good idea. But I too sometimes have found the .to_string()/.into() a bit heavy to write.


#7

In the long ago, we had this with the ~ sigil. e.g., You could write ~"foobar" and get back a ~str (which is now known as String). IIRC, people tended to use this too much, which is also a bad thing.

I agree that in tests you often want to be loosey goosey with this. I also think that a helper function is a pretty good solution to that.


#8

The simpler version, without needing to go through Cow, is just:

fn S<Str: Into<String>>(s: Str) -> String {
    s.into()
}

Or instead of defining a new function and sprinkling that everywhere, you could just add .into() on the end of ever &str you have that you want to use somewhere that expects a String:

"foo".into()

#9

It does? There is an impl Into<Vec<u8>> for String, which allows you to convert a String into a Vec<u8>, but none that allows you to convert a Vec<u8> into a String (including those derived from From implementations).


#10

Hmm, you’re right. In my defense, I’d only recently woken up.


#11

~“foobar”

hmm

would the box syntax be adequate? let x: String = box "my string";

http://is.gd/qvsEX9

it seems box x doesn’t use the box protocol yet but the desugared version seems to work.