How can I create a static String in Rust? [duplicate] - string

This question already has answers here:
How do I create a global, mutable singleton?
(7 answers)
Closed 3 years ago.
Is there a way I can create a static String in Rust?
I tried this:
static somestring: String = String::new();
but I got this error:
error: `std::string::String::new` is not yet stable as a const fn
--> src/main.rs:2:29
|
2 | static somestring: String = String::new();
|
How to create a static string at compile time does not solve my problem because it's about &'static str, not String. I need the String to be globally addressable.

Don't confuse the String type with the str type.
What are the differences between Rust's `String` and `str`?
A String is mutable and always heap-allocated.
A str, usually presented as &str is not mutable and is simply a view into a string.
Your question seems to confuse the idea of static and globally adressable. You may refer to (&'static str) as a string with a 'static lifetime. Strings with 'static lifetimes are common because they (mostly) represent hardcoded strings in the program. A 'static lifetime means the object (in this case, a string) will live until the end of the program. Most 'static objects are known at compile time. This should be natural to think about, because hardcoded strings are known at compile time. These strings can not mutate.
Strings on the other hand, are mutable. And you can make a String from a &'static str.
Given the lack of context in the question, if what you want is a String that is globally adressable and want to define it static I may suggest the macro lazy-static:
https://crates.io/crates/lazy_static
As sugested by mcarton, this question seems to boil down to the singleton pattern. You can learn more about its implementation in Rust here: How do I create a global, mutable singleton?

Related

Why would you convert from a string in Rust to a String?

I'm new to rust and comes from a python domain, I've just started learning rust, so I've 2 questions to ask. 1) Why are we defining "String" again (name: String) when already I have mentioned the datatype to be as "String" in my "struct Person". 2) What exactly is the use of from. Please could someone explain me in simple english.
fn main() {
struct Person {
name: String,
}
// instantiate Person struct
let person = Person {
name: String::from("Steve Austin"), //Why are we defining "string" again and "from"
};
// access value of name field in Person struct
println!("Person name = {}", person.name);
}
Why are we defining "String" again (name: String) when already I have mentioned the datatype to be as "String" in my "struct Person". 2) What exactly is the use of from.
You're not defining anything, String::from is a static function (think classmethod), which converts to a string.
It's a bit like calling str() in Python.
The oddity here is that Rust has multiple string-adjacent types, and String is only one of them: an owned, heap-allocated, mutable, string buffer. Python doesn't really have an equivalent, StringIO is probably the closest relative (strarray would be if it existed, but it does not).
Meanwhile string literals are not owned heap-allocated strings, instead they are references to data stored in the rodata (or text) segment of the binary.
Python has nothing which really compares, because its strings are more or less always heap-allocated and created at runtime, they're just immutable. The closest general equivalent to &str would be a string version of memoryview, but it still lacks the lexical constraints, and the idea of a 'static lifetime.
For more, see
https://doc.rust-lang.org/rust-by-example/std/str.html
https://stackoverflow.com/a/24159933/8182118
https://doc.rust-lang.org/std/primitive.str.html
https://doc.rust-lang.org/std/string/struct.String.html
In Rust there's two kinds of strings: str and String. The former is a really lean construct and is passed around as a reference, like &str. These cannot be modified.1 They also can't be copied, they're references, so they will always refer to the same value.
The reason they exist is because they are the "minimum viable string", they are the cheapest possible representation of textual data. This efficiency does have trade-offs.
A String can be modified if it's mut, and can also be copied, and later altered again. This makes them more suitable for properties that can and will change, or need to be computed at runtime.
Learning the difference here can be a bit bewildering if you're used to Python where strings are strings, but once you get a handle on it, you'll realize what's going on here.
"x" is a &str value, while String::from("x") is a String converted from that value. You can also do "x".into() if the type is well understood by the compiler, such as for a function argument or struct property.
Strings are also such a common thing that there's to_string() and to_owned(), both of which effectively do the same thing here on &str values.
If you want the best of both of these features, you can use Cow<str> which can encapsulate either an &str value, or a String, and you can convert from the "borrowed" value (&str) to an "owned" value via the to_owned() function.
These are more exotic, though, so I'd recommend only using them when you know what you're doing and need the performance gains they can offer.
--
1 Treat these like const char* in C++, versus std::string. The former is compiled into non-modifiable data in the executable, while the other uses a buffer that can be dynamically allocated.
In your example String::from() is not needed at all, it will work just fine without:
struct Person<'a> {
name: &'a str
}
fn main() {
let person = Person {
name: "Steve Austin"
};
println!("Person name = {}", person.name);
}
But it really depends on if your program would ever need to change Person.name and if you think that the struct should hold the data itself ("own" the data).
A str is a fixed string, it is stored in your executable and can be referenced in your program with a pointer & as a &str pointer. But it can not be modified.
In your case, "Steve Austin" can be used in your program as a &str.
In your example the name property is of type String. The contents of a String can be modified by your program because it lives in its own place in memory. This is where ownership comes in.
Rust will make sure that the String which is held by the struct lives long enough, by implicitly deriving both the lifetime of the struct and that of the String. Notice that to Rust, those are two different things. In your example, the struct really holds the data itself and so there is no question about what the lengths of the lifetimes should be.
In my example, Rust needs to be told the separate lifetimes for both the struct and the &str. Rust needs the &str to live (be present in memory) at least as long as the struct, because of the memory safety Rust offers via its borrow checker. This way the struct can not have a &str pointing to invalid memory (something that is not under control).
At first you might think that String in Rust is a pointer. But that is not the case. To Rust, String represents the data itself. When you want to reference that data, with a promise not to make modifications to it, you use a & (pointer). If you do want to make changes, you need to tell Rust your intention, and use a &mut (pointer to mutable data).
The difference of str and String in Rust will give you precise control over you program, and performance.

Rust difference between creating variables [duplicate]

This question already has answers here:
What are the differences between Rust's `String` and `str`?
(14 answers)
Closed 5 months ago.
I started learning rust and I'm unsure what is the difference between creating variables like this
let mut word = String::new();
and
let mut word = "";
and also
what is a variable which has & infront of it, thanks for your help I hope it's not a very stupid question.
There are two different string-like types in Rust.
String is the type of owned strings. If you have a String, you have total ownership over it. You can modify it, append to it, empty it, and, yes, even drop it. You can pass ownership to someone else, you can let someone else borrow it, and so on. If you take a reference to a String, you get a &String (an immutable reference to a String). This type is fairly useless, and most style checkers will warn you about that. On the other hand, the mutable reference of String, denoted &mut String, can be useful since the borrower can append to the string without taking ownership of it.
str is a string slice. It's an unsized type, so it can't be used as a function argument or a structure component without being wrapped in a reference or a Box. Most commonly, you see it in the form &str, which is an immutably-borrowed string slice. Since this is a reference, it's sized and thus can be used in most conventional contexts.
String::new returns, as the name implies, a new owned String. A string literal such as "" has type &'static str, i.e. a borrowed string slice with static lifetime.
You can borrow a String as a &str with as_str, or with the Deref instance for String. The latter will often kick in automatically if you try to call a str method on a String. On the other hand, there's no way to treat a &str as a String, since the former is borrowed and the latter implies ownership, a stronger guarantee. If you want to go the other way, you need to copy the data from the &str into a new String. This can be done in a couple of ways, simply by using different traits.
String::from(my_str)
my_str.to_owned()
Personally, I use String::from on string literals (i.e. String::from("some constant")) and to_owned on variables, but that's by no means a universal rule.
In summary, String is the type of owned strings, and &str is the type of borrowed string slices. String literals in Rust have type &'static str.

What is the relationship between slices and references in Rust?

I am completely new to Rust (as in I just started looking at it yesterday), and am working my way through "The Rust Programming Language". I'm a little stuck on Chapters 4.2 (References and Borrowing) / 4.3 (The Slice Type) and am trying to solidify my initial understanding of references before I move on. I'm an experienced programmer whose background is mainly in C++ (I am intimately familiar with several languages, but C++ is what I'm most comfortable with).
Consider the following Rust code:
let string_obj: String = String::from("My String");
let string_ref: &String = &string_obj;
let string_slice: &str = &string_obj[1..=5];
Based on my understanding, from the first line, string_obj is an object of type String that is stored on the stack, which contains three fields: (1) a pointer to the text "My String", allocated on the heap, encoded in UTF-8; (2) A length field with value 9; (3) A capacity field with a value >= 9. That's straightforward enough.
From the second line, string_ref is an immutable reference to a String object, also stored on the stack, which contains a single field - a pointer to string_obj. This leads me to believe that (leaving aside ownership rules, semantics, and other things I am yet to learn about references), a reference is essentially a pointer to some other object. Again, pretty straightforward.
It's the third line which causing me some headaches. From the documentation, it would appear that string_slice is an object of type &str that is stored on the stack, and contains two fields: 1) a pointer to the text "y Str", within the text "My String" associated with string_obj. 2) A length field with value 5.
But, by appearances at least, the &str type is by definition an immutable reference to an object of type str. So my questions are as follows:
What exactly is an str, and how is it represented in memory?
How does &str - a reference type, which I thought was simply a pointer - contain TWO fields (a pointer AND a length)?
How does Rust know in general what / how many fields to create when constructing a reference? (and consequently how does the programmer know?)
Slices are primitive types in Rust, which means that they don't necessarily have to follow the syntax rules of other types. In this case, str and &str are special and are treated with a bit of magic.
The type str doesn't really exist, since you can't have a slice that owns its contents. The reason for requiring us to spell this type "&str" is syntactic: the & reminds us that we're working with data borrowed from somewhere else, and it's required to be able to specify lifetimes, such as:
fn example<'a>(x: &String, y: &'a String) -> &'a str {
&y[..]
}
It's also necessary so that we can differentiate between an immutably-borrowed string slice (&str) and a mutably-borrowed string slice (&mut str). (Though the latter are somewhat limited in their usefulness and so you don't see them that often.)
Note that the same thing applies to array slices. We have arrays like [u8; 16] and we have slices like &[u8] but we don't really directly interact with [u8]. Here the mutable variant (&mut [u8]) is more useful than with string slices.
What exactly is an str, and how is it represented in memory?
As per above, str kind-of doesn't really exist by itself. The layout of &str though is as you suspect -- a pointer and a length.
(str is the actual characters referred to by the slice, and is a so-called dynamically-sized type. In the general case, a &T can't exist without a T to refer to. In this case it's a bit backwards in that the str doesn't exist without the &str slice.)
How does &str - a reference type, which I thought was simply a pointer - contain TWO fields (a pointer AND a length)?
As a primitive, it's a special case handled by the compiler.
How does Rust know in general what / how many fields to create when constructing a reference? (and consequently how does the programmer know?)
If it's a non-slice reference, then it's either a pointer or it's nothing (if the reference itself can be optimized away).

Can I get a String directly from split? [duplicate]

Is there any way to avoid calling .to_string() when I need a string? For example:
fn func1(aaa: String) -> ....
And instead of
func1("fdsfdsfd".to_string())
can I do something like this:
func1(s"fdsfdsfd")
TL;DR:
As of Rust 1.9, str::to_string, str::to_owned, String::from, str::into all have the same performance characteristics. Use whichever you prefer.
The most obvious and idiomatic way to convert a string slice (&str) to an owned string (String) is to use ToString::to_string. This works for any type that implements Display. This includes string slices, but also integers, IP addresses, paths, errors, and so on.
Before Rust 1.9, the str implementation of to_string leveraged the formatting infrastructure. While it worked, it was overkill and not the most performant path.
A lighter solution was to use ToOwned::to_owned, which is implemented for types that have a "borrowed" and an "owned" pair. It is implemented in an efficient manner.
Another lightweight solution is to use Into::into which leverages From::from. This is also implemented efficiently.
For your specific case, the best thing to do is to accept a &str, as thirtythreeforty answered. Then you need to do zero allocations, which is the best outcome.
In general, I will probably use into if I need to make an allocated string — it's only 4 letters long ^_^. When answering questions on Stack Overflow, I'll use to_owned as it's much more obvious what is happening.
No, the str::to_string() method is the canonical way of creating a String from an &'static str (a string literal). I even like it for the reason you dislike it: it's a little verbose. Because it involves a heap allocation, you should think twice before invoking it in cases such as these. Also note that since Rust gained impl specialization, str::to_string is no slower than str::to_owned or its ilk.
However, what you really want here is a func1 that can easily be passed any string, be it a &str or a String. Because a String will Deref to a &str, you can have func1 accept an &str, thereby avoiding the String allocation altogether. See this example (playground):
fn func1(s: &str) {
println!("{}", s);
}
fn main() {
let allocated_string: String = "owned string".to_string();
func1("static string");
func1(&allocated_string);
}
dtolnay:
I now strongly prefer to_owned() for string literals over either of to_string() or into().
What is the difference between String and &str? An unsatisfactory answer is “one is a string and the other is not a string” because obviously both are strings. Taking something that is a string and converting it to a string using to_string() seems like it misses the point of why we are doing this in the first place, and more importantly misses the opportunity to document this to our readers.
The difference between String and &str is that one is owned and one is not owned. Using to_owned() fully captures the reason that a conversion is required at a particular spot in our code.
struct Wrapper {
s: String
}
// I have a string and I need a string. Why am I doing this again?
Wrapper { s: "s".to_string() }
// I have a borrowed string but I need it to be owned.
Wrapper { s: "s".to_owned() }
vitalyd:
Not if you mentally read to_string as to_String

How to create a String directly?

Is there any way to avoid calling .to_string() when I need a string? For example:
fn func1(aaa: String) -> ....
And instead of
func1("fdsfdsfd".to_string())
can I do something like this:
func1(s"fdsfdsfd")
TL;DR:
As of Rust 1.9, str::to_string, str::to_owned, String::from, str::into all have the same performance characteristics. Use whichever you prefer.
The most obvious and idiomatic way to convert a string slice (&str) to an owned string (String) is to use ToString::to_string. This works for any type that implements Display. This includes string slices, but also integers, IP addresses, paths, errors, and so on.
Before Rust 1.9, the str implementation of to_string leveraged the formatting infrastructure. While it worked, it was overkill and not the most performant path.
A lighter solution was to use ToOwned::to_owned, which is implemented for types that have a "borrowed" and an "owned" pair. It is implemented in an efficient manner.
Another lightweight solution is to use Into::into which leverages From::from. This is also implemented efficiently.
For your specific case, the best thing to do is to accept a &str, as thirtythreeforty answered. Then you need to do zero allocations, which is the best outcome.
In general, I will probably use into if I need to make an allocated string — it's only 4 letters long ^_^. When answering questions on Stack Overflow, I'll use to_owned as it's much more obvious what is happening.
No, the str::to_string() method is the canonical way of creating a String from an &'static str (a string literal). I even like it for the reason you dislike it: it's a little verbose. Because it involves a heap allocation, you should think twice before invoking it in cases such as these. Also note that since Rust gained impl specialization, str::to_string is no slower than str::to_owned or its ilk.
However, what you really want here is a func1 that can easily be passed any string, be it a &str or a String. Because a String will Deref to a &str, you can have func1 accept an &str, thereby avoiding the String allocation altogether. See this example (playground):
fn func1(s: &str) {
println!("{}", s);
}
fn main() {
let allocated_string: String = "owned string".to_string();
func1("static string");
func1(&allocated_string);
}
dtolnay:
I now strongly prefer to_owned() for string literals over either of to_string() or into().
What is the difference between String and &str? An unsatisfactory answer is “one is a string and the other is not a string” because obviously both are strings. Taking something that is a string and converting it to a string using to_string() seems like it misses the point of why we are doing this in the first place, and more importantly misses the opportunity to document this to our readers.
The difference between String and &str is that one is owned and one is not owned. Using to_owned() fully captures the reason that a conversion is required at a particular spot in our code.
struct Wrapper {
s: String
}
// I have a string and I need a string. Why am I doing this again?
Wrapper { s: "s".to_string() }
// I have a borrowed string but I need it to be owned.
Wrapper { s: "s".to_owned() }
vitalyd:
Not if you mentally read to_string as to_String

Resources