What is the r#""# operator in Rust?
I saw the operator r#""
in Rust but I can't find what it does. It came in handy for creating JSON:
let var1 = "test1";
let json = r#"{"type": "type1", "type2": var1}"#;
println!("{}", json) // => {"type2": "type1", "type2": var1}
What's the name of the operator r#""
? How do I make var1
evaluate?
I can't find what it does
It has to do with string literals and raw strings. I think it is explained pretty well in this part of the documentation, in the code block that is posted there you can see what it does:
"foo"; r"foo"; // foo "\"foo\""; r#""foo""#; // "foo" "foo #\"# bar"; r##"foo #"# bar"##; // foo #"# bar "\x52"; "R"; r"R"; // R "\\x52"; r"\x52"; // \x52
It negates the need to escape special characters inside the string.
The r
character at the start of a string literal denotes a raw string literal. It's not an operator, but rather a prefix.
In a normal string literal, there are some characters that you need to escape to make them part of the string, such as "
and \
. The "
character needs to be escaped because it would otherwise terminate the string, and the \
needs to be escaped because it is the escape character.
In raw string literals, you can put an arbitrary number of #
symbols between the r
and the opening "
. To close the raw string literal, you must have a closing "
, followed by the same number of #
characters as there are at the start. With zero or more #
characters, you can put literal \
characters in the string (\
characters do not have any special meaning). With one or more #
characters, you can put literal "
characters in the string. If you need a "
followed by a sequence of #
characters in the string, just use the same number of #
characters plus one to delimit the string. For example: r##"foo #"# bar"##
represents the string foo #"# bar
. The literal doesn't stop at the quote in the middle, because it's only followed by one #
, whereas the literal was started with two #
.
To answer the last part of your question, there's no way to have a string literal that evaluates variables in the current scope. Some languages, such as PHP, support that, but not Rust. You should consider using the format!
macro instead. Note that for JSON, you'll still need to double the braces, even in a raw string literal, because the string is interpreted by the macro.
fn main() {
let var1 = "test1";
let json = format!(r#"{{"type": "type1", "type2": {}}}"#, var1);
println!("{}", json) // => {"type2": "type1", "type2": test1}
}
If you need to generate a lot of JSON, there are many crates that will make it easier for you. In particular, with serde_json
, you can define regular Rust structs or enums and have them serialized automatically to JSON.
The first time I saw this weird notation is in glium tutorials (old crate for graphics management) and is used to "encapsulate" and pass GLSL code (GL Shading language) to shaders of the GPU
https://github.com/glium/glium/blob/master/book/tuto-02-triangle.md
As far as I understand, it looks like the content of r#...# is left untouched, it is not interpreted in any way. Hence raw string.