Rust for PHP Developers (Part 2)

1. Complex Types

1.1. Arrays

In PHP, arrays are the most commonly used data structure, and they differ greatly from traditional arrays in most other programming languages and Rust is no exception. In Rust, arrays are fixed-size collections of elements of the same type. The size of an array is part of its type, so you can’t change the size of an array once it’s declared (too bad, PHP developers).

Here’s how you can declare an array in Rust:

let arr: [i32; 3] = [1, 2, 3]; // can work without type annotation as well

A fixed sized array might sound limiting but Rust has a bunch of other data structures that can be used in place of arrays. One of them is the Vec type which is a dynamically sized array. Here’s how you can declare a Vec in Rust:

let vec: Vec<i32> = vec![1, 2, 3];

In the above example is the type of the elements in the vector. This is part of Generics, which I feel is one of the things that PHP should have.

1.2. Tuples

Not found in PHP, a tuple is a fixed-size collection of elements of different types. Here’s how you can declare a tuple in Rust:

let tup = (500, 6.4, 1);
let crazy_tuple = ("hello", 5, 6.4, 'c', vec![1, 2, 3]); // tuple with different types

each element in the tuple can be accessed using the dot notation followed by the index of the element. For example, tup.0 will return 500tup.1 will return 6.4, and tup.2 will return 1.

Note: In all examples I am omitting fn main() {} for brevity, you can add that along with println! to see the outputs

1.3. Structs & Enums

Structs are custom data types that let you name and package together multiple related values. Here’s how you can declare a struct in Rust:

struct User {
    email: String,
    sign_in_count: u64,
    active: bool,
}

let user1 = User {
    username: String::from("codisfy"),
    active: true,
    sign_in_count: 1,
};

println!("{}", user1.username); // prints codisfy

Consider them to be distant siblings of PHP classes. They are similar in the sense that they can have methods and properties, but they are different in the sense that they can’t have inheritance or polymorphism.

PHP 8.1 introduced Enums(I am yet to use them). Enums lets you define a type by enumerating its possible variants. Here’s how you can declare an enum in Rust:

enum FavColor {
    Red,
    Green,
    Blue,
}

let color = FavColor::Red;

There’s more to enums in Rust, as you can associate data with each variant, however for the sake of simplicity, I’ll leave it at that.

Both Enums and Structs can have methods, which is a great way to encapsulate logic. Here’s how you can define a method for a struct in Rust:

impl User {
    fn get_username(&self) -> &String {
        &self.username
    }
}

impl FavColor {
    fn get_color(&self) -> &str {
        match self {
            FavColor::Red => println!("Favorite color is Red"),
            FavColor::Green => println!("Favorite color is Green"),
            FavColor::Blue => println!("Favorite color is Blue"),
        }
    }
}

println!("{}", user1.get_username()); // prints codisfy

color.get_color(); // prints Favorite color is Red

2. Control Flow

2.1. If Statements

Very similar to PHP however you don’t have to use () around the condition.

2.2. Match Statements

match statements have already been introduced in PHP 8.0, they are pretty similar however in Rust they match “patterns” rather than values.

For example when I read the following code it didn’t make sense to me at first:

let x = Some(5);
let y = 10;

match x {
    Some(50) => println!("Got 50"),
    Some(y) => println!("Matched, y = {:?}", y),
    _ => println!("Default case, x = {:?}", x),
}

The output of the above code will be Matched, y = 5. the Some(y) pattern matches the value of x and assigns it to y inside the match block. A little confusing right?
y inside the match arm is a new pattern variable and captures the value of x.

3. Loops

3.1. Loop

The most basic loop construct in Rust is the loop keyword. It will run the code inside the loop block indefinitely until you break out of it.

let mut counter = 0;
'my_loop: loop { // label the loop as my_loop, handy for breaking out of nested loops
    counter += 1;
    if counter == 10 {
        break 'my_loop; // doesn't have to be labeled, but just to show usage
    }
}

With the loop you can also use break to return a value from the loop.

let mut counter = 0;

let result = loop {
    counter += 1;

    if counter == 10 {
        break counter * 2; // return a value from the loop, making result = 20
    }
};

3.2. While Loop

The while loop is similar to PHP, it will run the code inside the loop block as long as the condition is true.

3.3. For Loop

Different to PHP, Rust’s for loop is used to iterate over a range of values.

for number in (1..4) { // use an '_' instead of a variable name `number` if you don't need it
    println!("{}", number);
}

I believe this should already be giving you a sense of Rust. There are many interesting concepts that you won’t find in PHP, Generics and Traits are some of them. I will cover them in Part 3.

Leave a Reply

Your email address will not be published. Required fields are marked *