doliphin
doliphin

Reputation: 1014

Is there any use for `str` in Rust?

Is there any case where one would use str without borrowing it? Does that even make sense?

I understand the difference between String and &str, but since there is &str there must also be str?

Upvotes: 3

Views: 532

Answers (2)

Sören
Sören

Reputation: 879

Because str is unsized (?Sized) meaning the size at compile time is not known. You can only use it in places where ?Sized is allowed. That is the case in Box.

let s: &str = "any string";
let box: Box<str> = Box::from(s);

Because box allocates data on the heap, it does not care if the size of the type is not known at compile time.

You can see Box<str> used in String::into_boxed_str, which is useful if you want to say, I'm finished with generating the string and don't want to be able to add anything to it. Additionally it removes the capacity field which String needs, which saves a bit of memory. However I haven't really seen this used very much.

Most places where you will see a str without the & before are in traits with generic types. For example when implementing AsRef.

pub struct CustomString(String);

impl AsRef<str> for CustomString {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

Sidenote: str behaves similarly to a slice [T] it to is unsized (?Sized).

Upvotes: 4

Peter Hall
Peter Hall

Reputation: 58715

You can't do much with a value of type str, but there are plenty of cases where you would want to refer to the type str.

  • Box<str> or Rc<str> - owned types, similar to String, but can't be mutated to grow or re-allocate

  • Any time you want to accept an arbitrary type that can be viewed as a string, you could use constraints like T: Deref<Target = str>, T: AsRef<str> or T: Borrow<str>. For example HashMap::get has the following signature:

    pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where
      K: Borrow<Q>, // K is the key type for the HashMap
      Q: Hash + Eq, 
    

    This means you can have a HashMap<String, i32>, but access values with a &str key, e.g. map.get("key"). Here Q would be inferred to be str, but the k argument would still be a &str (&Q).

    The ?Sized annotation means that Q does not need to have a size known at compile-time, explicitly allowing unsized types like str to be used.

Upvotes: 8

Related Questions