This post published on my blog before
Hi everyone. Before that, I wrote a post called Rust’s Borrowing and Reference Laws.
Today I'll try to explain the slice type in Rust
Before starting, I’ll create a project with cargo;
cargo new slice_type
cd slice_type
Introduction
If you worked with languages like Python, you are familiar with slices. Slices don't have ownership in Rust. When you work with slices, you think about a contiguous sequence of an element like a string.
For example, we're using slices in Python like that;
py_string='Python'# contains indices 0, 1 and 2
print(py_string[0:3])# Pyt
We're calling this as indexing syntax.
Let's Back to the Rust Side
Let's assume we have a function like below. In this section, we'll use Rust's example.
fnfirst_word(s:&String)->usize{letbytes=s.as_bytes();for(index,&item)inbytes.iter().enumerate(){ifitem==b' '{returnindex;}}s.len()}
In the above example, we've created a function called first_word
. It doesn't have ownership. So, that's what we want. The Rust asking us what should we return? Is this a real question? I don't think so. However, in this example, we're trying to return an index or a length value for the whole string.
This function will return a byte index value according to example. We're converting our string to an array of bytes using as_bytes()
method.
letbytes=s.as_bytes();
In the above line, we've created an array of bytes from a string. The next line is about iteration. We will not discuss the enumerate()
method in this post. For now, we should know that iter()
is a method that returns each element in a collection. So, the enumerate()
method wraps the result of iter and returns each element as part of a tuple instead.
for(i,&item)in
In the above section, we're destructing a tuple. The first value of tuple is representing index
and the second is representing value
. Because we get a reference to the element from .iter().enumerate()
, we use &
in the pattern.
ifitem==b' '{returnindex;}
In the above lines, we're checking whether the item
equals to space or not. For example, if you passed Hello world!
, this block will run and return the last index. If you passed Helloworld!
, s.len()
will return. Let's complete our example;
fnmain(){lets=String::from("Hello world");letindex=first_word(&s);println!("Index {}",index);}fnfirst_word(s:&String)->usize{letbytes=s.as_bytes();for(index,&item)inbytes.iter().enumerate(){ifitem==b' '{returnindex;}}s.len()}
Guess what will return :) It will return 5. Because in this example, we're looking for a space character. And that space is coming after o
.
String Slices
Each string consists of slices. I mean, each character is a slice. Let's assume we have a string like that;
Hello world
. We also have slices by this example. These are;
INDEX | VALUE |
---|---|
0 | H |
1 | e |
2 | l |
3 | l |
4 | o |
5 | |
6 | w |
7 | o |
8 | r |
9 | l |
10 | d |
When you want to get a part of a string, you should use a range within brackets by specifying. For example;
lethello=String::from("Hello world");letstart_index=0;letlast_index=5;lethello=&hello[start_index..last_index];
You can also use .get()
method. But &T
and .get()
are different. So, we know how we can get a range from a string. Let's say we want to get a string after the specified letter. How can we do that?
fnmain(){lets=String::from("Hello world");letletter=String::from(" ");letindex=first_word(&s,&letter);println!("The string is {}",&s[index..]);}fnfirst_word(s:&String,l:&String)->usize{letbytes=s.as_bytes();letletter=l.as_bytes();for(index,&item)inbytes.iter().enumerate(){ifitem==letter[0]{returnindex;}}s.len()}
That's what we want :) You don't have to specify ending or starting index always. You can use like that;
&your_var[start_index..];&your_var[..end_index];&your_var[..];
- The first example will get string starting the index you specified.
- The second example will get string until the index you specified.
- The last example will return the whole string.
Note: String slice range indices must occur at valid UTF-8 character boundaries. If you attempt to create a string slice in the middle of a multibyte character, your program will exit with an error.
Other Type Slices
String slices were strings. But slices can be used for other types. Let's create a u8 array.
fnmain(){letnumber_array=[1,5,7,9,11,13,15,17,19,21];println!("Numbers: {:?}",&number_array[1..3]);}
It will return Numbers: [5, 7]
.
So, according to this example, we can create other types of slices.
fnmain(){letan_array=[true,true,false,true,false,false,true,false];println!("Array values: {:?}",&an_array[1..3]);}
That's all for now. If there is something wrong, let me know.
Thanks for reading