24

In the nightly Rust it is no longer possible to designate a string literal as String with a "~" character.

In C++, for example, I'm using user-defined literals to concatenate string literals without the crust of mentioning std::string every time:

inline std::string operator"" _s (const char* str, size_t size) {return std::string (str, size);} foo ("Hello, "_s + "world!"); 

Is there a similar feature existing or planned in Rust to make string literal concatenation less painful than String::from_str ("Hello, ") + "world!"?

8
  • The simple answer for now is “no”. May I ask why you want to do this? Commented Aug 15, 2014 at 14:38
  • 1
    To improve readability. Commented Aug 15, 2014 at 14:42
  • @ChrisMorgan In a wider context, user-defined literals promote strong typing by making it less painful to introduce and read the types in the code. It's the same way Rust uses 123u32 123i64 instead of static_cast<uint32_t>(123) to promote strong typing. Now, writing String::from_str every time is like writing static_cast<uint32_t>(123) every time. Commented Aug 15, 2014 at 15:23
  • 2
    Why do you want to concatenate string literals? Can you just write them out as a single literal? Commented Aug 15, 2014 at 21:38
  • 1
    @dbaupp You've got to be kidding me. Of course not! Concatenating string literals is my bread and butter, what would I do at work if I just write them as a single literal? Commented Aug 16, 2014 at 5:26

3 Answers 3

51

If you literally (hah) have string literals, you can use the concat! macro:

let lit = concat!("Hello, ", "world!") 

You can natively split strings over several lines:

let lit = "Hello, \ World"; 

The \ consumes all following whitespace, including the leading spaces on the next line; omitting the \ will include the string data "verbatim", with newlines and leading spaces etc.

You can add a &str to a String:

let s = "foo".to_string() + "bar" + "baz"; 

You could use push_str iteratively:

let mut s = "foo".to_string(); s.push_str("bar"); s.push_str("baz"); 

You could use SliceConcatExt::concat:

let s = ["foo", "bar", "baz"].concat(); 

If all else fails, you can define a macro to do exactly what you want.

See also:

Sign up to request clarification or add additional context in comments.

Comments

18

You can use the format! macro. It is more readable, more translation-friendly, more efficient, and more powerful (you can concatenate more than just strings, just like C++'s ostringstream). It is also completely type-safe.

format!("Hello, {}", "world!") 

You can also use named arguments to improve readability.

format!("hello, {who}", who = "world") 

The full formatting syntax is described in std::fmt.

Rust does not have user-defined literals. I think adding such a feature is backward-compatible, so maybe this feature will be added after Rust 1.0.

4 Comments

Thanks for the answer. I like how Rust makes such things possible, but if we speak about the program readability then these printf variants all suffer from the problem of shuffling things around instead of keeping them in the natural order. When building a complex string, such as an SQL query, a version that keeps the things in place, like the one described here blog.moertel.com/posts/… (safe-string kernel), is preferable.
I should also mention the string interpolation in Scala that avoids the shuffling problem as well: slick.typesafe.com/doc/2.0.0-M3/sql.html#string-interpolation - the variables are automatically escaped there (or rather, bound into a prepared query) pretty much like in the Haskell version, although the former is more powerful.
@ArtemGr, it should be possible to write a macro that does preparation/interpolation in a similar way (example of syntax); the type system is certainly powerful enough to express the concepts like safe strings.
@dbaupp That's a music to my ears, I might invest some time into learning the Rust macro system then, thanks.
1

You can concatenate str literals without using String with the concat! macro:

let input = concat!("Hello", ' ', "world"); 

To make it a string, specify the destination type and use into:

let input: String = concat!("Hello", ' ', "world").into(); 

Full program:

fn main() { let input: String = concat!("Hello", ' ', "world").into(); println!("{}", input); // Output: Hello world } 

1 Comment

concat! is already shown by the highest-voted answer. This answer doesn't really add anything valuable.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.