A Slice of Rust: Working with the Slice Type
Tags: rust, tutorial, learning, programming
Published: 2020-08-03 13:50:20

*This post published on my blog [before](https://aligoren.com/a-slice-of-rust-working-with-the-slice-type/)*

-----

Hi everyone. Before that, I wrote a post called [Rust’s Borrowing and Reference Laws](https://dev.to/aligoren/rust-s-borrowing-and-reference-laws-29go).

Today I'll try to explain the slice type in Rust

Before starting, I’ll create a project with cargo;

```bash
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;

```python
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.

```rust
fn first_word(s: &String) -> usize {
    let bytes = s.as_bytes();

    for (index, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return index;
        }
    }

    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.

```rust
let bytes = 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.

```rust
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.

```rust
if item == b' ' {
            return index;
        }
```

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;

```rust
fn main() {
  let s = String::from("Hello world");

  let index = first_word(&s);

  println!("Index {}", index);
}

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

    for (index, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return index;
        }
    }

    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;

```rust
let hello = String::from("Hello world");

let start_index = 0;
let last_index = 5;

let hello = &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?

```rust
fn main() {
    let s = String::from("Hello world");
    let letter = String::from(" ");
    
    let index = first_word(&s, &letter);

    println!("The string is {}", &s[index..]);
}

fn first_word(s: &String, l: &String) -> usize {
    let bytes = s.as_bytes();
    let letter = l.as_bytes();

    for (index, &item) in bytes.iter().enumerate() {
        if item == letter[0] {
            return index;
        }
    }

    s.len()
}
```

That's what we want :) You don't have to specify ending or starting index always. You can use like that;

```rust
&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.

```rust
fn main() {
  let number_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.

```rust
fn main() {
  let an_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

## Resources

- [The Slice Type](https://doc.rust-lang.org/book/ch04-03-slices.html)