In this article, we will learn how to write simple functions in rust. By writing these simple functions we will understand if/else blocks, loops and how to define functions.

Here is a C program with a simple function which prints “Hello world\n”.


void hello_world() {
    printf("Hello world\n");
}
void main() {
    hello_world();
}

Here is the same program converted into rust.


fn hello_world() {
    println!("Hello world");
}
fn main() {
    hello_world();
}

Apart from the fn keyword in rust the function definition is same in both languages if the function does not take any arguments and does not return anything. Function invocation is also almost identical.

Lets convert another small C program into rust and see how different parts of a program maps into rust language.


int add(int a, int b) {
    return a + b;
}
void main() {
    printf("Result %d\n", add(1, 2));
    printf("Result %d\n", add(3, 4));
}

The `add` function takes two arguments of type integer. In rust, to represent a integer you can use one of the following data type – u8, u16, u32, u64, u128 or usize(similarly you have signed equivalent – i8, i16, i32, i64, i128 or isize). We will use u32 for this program.


fn add(a: u32, b: u32) -> u32{
    return a + b;
}
fn main() {
    println!("Result = {}", add(1, 2));
    println!("Result = {}", add(3, 4));
}

Few things can be observed in the program:
1. Function argument format is arg_name: data_type
2. Function return value is defined by using `->`
Although the above program compiles and runs, the following format is preferred.


fn add(a: u32, b: u32) -> u32{
    a + b
}

The only change is the removal of return keyword and the semi-colon. Don’t worry about this you will get to use to this or you can continue to use explicit return keyword.

Lets take a look at another C program.


const float pi = 3.14;
float circumference(int radius) {
    return 2 * pi * radius;
}
int main() {
    printf("Result: %4.2f\n", circumference(18));
    return 0;
}

The equivalent rust program is


const PI:f32 = 3.14;
fn circumference(radius:u32) -> f32 {
    (2 as f32) * PI * (radius as f32)
}
fn main() {
    println!("Result: {:4.2}", circumference(18));
}

The main difference between above rust and C programs are:
1. Rust prefers the constant names to be in upper case letters.
2. Rust requires cast operation to apply arithmetic operations between integer and float.


Now, lets write a rust program with loop and conditional statements. The following program finds greatest common divisor for given two numbers. Try to convert this into rust program assuming while and if condition syntax is same as C and compile and run using cargo run command.


int gcd(int num1, int num2) {
    while (num1 != num2) {
        if (num1 > num2)
            num1 -= num2;
        else
            num2 -= num1;
    }
    return num1;
}
int main() {
    printf("Result: %d\n", gcd(18, 24));
    printf("Result: %d\n", gcd(21, 24));
    return 0;
}

Most likely “cargo run” might have thrown an error and guided you to make num1 and num2 as mutable argument. The reason for this is in rust all variables are immutable unless specified as mutable.


fn gcd(mut num1: i32, mut num2: i32) -> i32 {
    while num1 != num2 {
        if num1 > num2 {
            num1 -= num2;
        } else {
            num2 -= num1;
       }
    }
    num1
}
fn main() {
    println!("Result: {}", gcd(18, 24));
    println!("Result: {}", gcd(21, 24));
}

Now try calling gcd(18, -24); in both C and rust and observe the behavior. I will cover that in another article.

We will see one more program to explain how bit operations work in rust.


fn main() {
    let mut byte: u8 = 0b0000_0000;
    println!("Original byte:            {byte:#010b}");
    for i in 0..8 {
        // Modulo operation is same as C.
        if (i % 2) == 0{
            continue;
        }
        // OR operation and shift operations are same as C.
        byte |= 1 << i;
    }
    println!("After even bits are set:  {byte:#010b}");
    // NOT operator is different than C.
    byte = !byte;
    println!("After NOT operation:      {byte:#010b}");
    byte &= 0b1111_0000;
    println!("After AND operation:      {byte:#010b}");
}

The main take away from the above program is all C operators are same in Rust except the NOT ~ operator.
Bit operations in rust is little easier to read since we can group the bits like 0b1101_0001_0111_1111.

This article can be viewed as video here

Categorized in:

Tagged in:

,