- In this section,
we're going to dig deeper into how strings work.
We've talked a little bit about strings already,
and now that we understand borrowing,
we're going to look at it in more detail.
Quite a confusing area for Rust developers,
when they get started,
the fact that Rust actually has two different string types.
First of all, it has string as a structure.
This is a standard structure in Rust
and it's the primary way that you create strings.
When you create the string object, it owns text,
it owns the text allocated on the heap.
So a string object would own text on the heap
and potentially could change it,
you know, if it was mutable,
and would be responsible for de-allocating it
when the string is dropped.
So this is the main way
of holding text in your application
that you want to own and change.
That's the way to do it.
But there's another type called str,
with a lowercase S,
and this is a primitive type in Rust.
It's a fact pointer, basically.
It basically represents a slice of text somewhere.
It doesn't own the text,
it's just a slice of text.
So a str would be basically like a pointer
to a part of some text allocated elsewhere.
It just points to a bite, like the letter E,
and it knows how big it is,
but it doesn't own the text.
It's just an observer of that little window of text.
So we need to discuss how the string structure
and the str slice interact with each other,
because they do interact with each other.
So first of all, let's take a look at this example.
I'm going to borrow a string object.
So first of all, I've declared a string object, obj,
and here it is, it's a string object
and it contains the text hello, right here.
And then in red, you can see here,
I've taken a reference to the object
and I've stored that reference in S.
So let's think about the data types involved here.
So first of all, when I say &obj
that's taken a reference to a string,
or as a Rust developer,
I would say we're borrowing the string.
So the type of &obj
is a string reference, okay?
So this is a string reference.
And then what about S?
I haven't typed it explicitly.
So implicitly it will also be a string reference.
So S is a reference to the whole string
like that, okay?
And you know, if I'd set this up as being mutable
then I could have modified the whole string object via S.
So that's quite straightforward actually.
Let's take things a step further
and see what happens
if you use this syntax, which you can.
Let's see what happens here.
So again, obj is a string object.
So let's just draw that here,
holds the text, hello,
like so that's the text on the heap.
Let's consider the types involved
in my red statement here.
So first of all, on the right hand side,
I've taken a reference to a string object, okay?
So that kind of is like a reference
to the whole string
but you'll notice that when I declare the variable,
when I , oops, let me just draw my object again.
When I declare the variable here
I give it a type &str, okay?
So that's a string slice.
So technically, S is a slice into the string.
Initially, it's like a fat pointer,
well, it's a fat pointer.
S will be a pointer
to the first bite in the string
and it'll know that the string is five characters.
So at the moment, I've set up S
to refer to this slice of text effectively,
but what I could do
is I could change S to be a sub-portion.
So for example, I could change my slice.
So that instead of being the whole string,
maybe it points to the letter E
and maybe it only holds two characters, okay?
So as far as the string slice is concerned now,
the string slice would only be this bit here, okay?
So you can see where the terminology a slice comes,
the string is hello,
but you can look at a little slice of it,
just the few characters if you want to.
Right, now, here's an important thing.
Here's a fact, the compiler
is capable of automatically converting
a string reference into a string slice.
So that's needs further investigation.
If you borrow a string object,
in other words if you say something like a &S1,
you can assign it into a str slice.
Okay, so you could declare a variable,
let I call it string slice 1,
as a string slice, &str.
Like that, and that's actually exactly what we did
on the previous slide.
I've got a string object, S1
that holds the actual text, hello, let's say.
And then on the left hand side,
I've taken a reference to the string,
but I've stored it in a string slice.
So SS1, string slice 1
isn't a pointer to the whole string,
it is rather a string slice
into the actual text like that.
And it knows not only the pointer
but how big the text is as well, like that.
So there's an automatic conversion
between a string reference and a string slice.
And that's what we've got here.
So we've got the object, which is hello,
and this is a,
this type here is &String.
It's a reference to string object.
I can quite happily assign it to this variable
on the left hand side,
which has type string slice.
Okay, so S basically refers just into the text itself
not to the actual string object itself.
So you have to kind of think about this a little bit
and kind of work the idea through in your mind.
It's quite handy when you write in functions
because if you have a function that takes this type,
you can either pass in literal text
or you can pass in a whole string object.
So that can be quite useful.
So let's take a look at that.
Here's a literal text.
When you have literal text,
the technical data type of literal text
is a string reference, a string slice.
The static keyword here
is just indicated in the lifetime
of the text is permanently allocated.
When you have a string literal like hello
it's never gonna disappear.
It's just fixed memory.
So it shows, it just indicates
that the lifetime of the text
you're referring to is static
will always be there, okay?
So this is a literal text.
This here is a string slice.
Technically S is, would look like this.
It would have a pointer to the letter H
and it would know that there are five letters in H, okay?
So that's basically what the string slice is.
It's points to the string literal.
So let's see an example
to put this into practice,
lesson07_borrowing demo_string_slice_intro.
We'll look at the code and then we'll run it as usual.
Let's see.
So here's the code in my main.rs.
I'm going to uncomment demo_string_slice_intro.
And here it is.
Right, so I've got a couple of functions,
string slices with objects
and string slices with literals.
So here we go.
Here is my string object.
And this is a,
this variable here implicitly
is a &String.
I can take that
and also refer it to a string slice.
So S1 has type
reference to string.
And S2 explicitly
has type string slice, okay?
So you can take a reference to a string object
and store it in a string reference,
or you can store it in a string slice.
And in both cases it would print hello.
And then in my second example,
here this is a string literal.
And a string literal implicitly is a string slice.
When you assign a string literal
this variable here is implicitly a slice.
It knows the address of the H
and it knows how many characters there are, five.
And if you want to be explicit about it,
you could say, here's a string literal
and let's assign it to a string slice.
In practice, nobody ever bothers typing explicitly
a string literal, okay?
It's quite okay to leave it like this.
So in practice, I wouldn't bother
with explicit typing because it's just too much effort
unless you really wanted to prove the point, like so.
Right, so when I run the application it's gonna work.
What we're gonna do in the next section
is we're gonna see some applications
of string slices in practice.
Let's just run it for now.
There we go.
Right, so to summarize
this introduction to string slices,
you start off with a real string object.
You can take a slice of that string object.
You can also take a slice from string literal, okay?
So S3 is a string slice.
S4 is a string slice,
a slice into existing text,
as is S2, it's a slice into the text
of an existing string object.
So that gives you an introduction.
And what we'll do in the next lesson
is go into it in more detail
and see why this might be useful.