String slice vs String type

Hi, I'm new to rust. I started with The Rust Programming Language and I'm reached the slice type chapter.

I'm struggling to understand the type checking in the following snippet:

fn main() {

  let s = String::from("hello world");

  let word = first_word(&s);


  println!("first word {}", word);
}

fn first_word(s: &str) -> &str {
  let bytes = s.as_bytes();

  for (i, &item) in bytes.iter().enumerate() {
      if item == b' ' {
          return &s[0..i];
      }
  }

  &s
}

The code compiles correctly but for me it should raise an error about the first_word function is receiving a &String and not a &string (the string type should be different from string slice, not?).

Could anyone explain why this snippet compiles correctly?.

P.D.
I'm using rustc 1.45.2

This is about ownership. String type owns its data, and the data will be gone when the String goes out of scope. It's always an independent, whole object.

&str is only a temporary read-only view into some String that exists elsewhere. It can't exist on its own, and can't be used for longer than lifetime of the String it borrows from (&'static str for string literals is a bit of an odd case, because it borrows from program's own executable). It can view only a fragment of another string, and can be duplicated and destroyed at will without affecting anything.

In C String would be char * from malloc() that you must call free() on, and &str would be const char * that you must never ever call free() on.

In C++ std::string equivalent is String, and std::string_view is &str.


&String as a type is never used if it's possible to avoid it. It's a double indirection, and it doesn't make sense to ever use it, because it's a read-only borrow of a growable string which can't be grown due to the borrow.

5 Likes

What’s happening here is a coercion, in particular you can coerce

&T or &mut T to &U if T implements Deref<Target = U> .

And coercion can happen at coercion sites, in particular for:

Arguments for function calls
The value being coerced is the actual parameter, and it is coerced to the type of the formal parameter.

In the standard library the type String implements Deref with a Target = str ⟶ here.

This is why your code compiles even though you are passing a &String to a function expecting a &str.

I want to second and amend @kornel’s note that &String should be avoided, because it doesn’t give you any advantages over &str and also since a function expecting &str can just as well accept &String but not vice versa (so your functions are more general i.e. more useful when they take &str).

8 Likes

I understand perfectly.

Thank you very much!.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.