2
\$\begingroup\$

I started writing Rust by doing a simple program that will print all prime numbers until it reaches the upper bound that is provided through standard input. Here is my code

use std::io;

fn main() {
    println!("Enter a number: ");
    let mut limit = String::new();
    io::stdin().read_line(&mut limit).expect("failed to read line");
    let limit: u64 = limit.trim().parse().expect("Please enter a number.");
    if limit <= 0 {
        println!("Number must be greater than or equal to 0.");
    } else {
        let mut is_prime = 0;
        for n in 2..limit+1 {
            if n < 4 {
                is_prime = 1;
            }
            if n % 2 == 0 && n != 2 {
                continue;
            }
            if n % 3 == 0 && n != 3 {
                continue;
            }
            is_prime = 1;
            let mut m = 5;
            while m <= (n as f64).sqrt() as u64 {
                if n % m == 0 {
                    is_prime = 0;
                    break;
                }
                if n % (m + 2) == 0 {
                    is_prime = 0;
                    break;
                }
                m += 6;
            }
            if is_prime == 1 {
                println!("{}", n);
            }
        }
    }
}

While the program does compile and run without any issues, there are two warnings that come up when I compile. This isn't the biggest concern of my program, but is merely just worth mentioning.

$ rustc primes.rs            
primes.rs:11:13: 11:25 warning: value assigned to `is_prime` is never read, #[warn(unused_assignments)] on by default
primes.rs:11         let mut is_prime = 0;
                         ^~~~~~~~~~~~
primes.rs:14:17: 14:25 warning: value assigned to `is_prime` is never read, #[warn(unused_assignments)] on by default
primes.rs:14                 is_prime = 1;
                             ^~~~~~~~
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$
primes.rs:11:13: 11:25 warning: value assigned to `is_prime` is never read, #[warn(unused_assignments)] on by default
primes.rs:11         let mut is_prime = 0;
                         ^~~~~~~~~~~~

You don't have to initialize a variable when you declare it. That is, you can write

let mut is_prime;

You just have to initialize it before reading from it; if the compiler cannot guarantee that the variable will be initialized at that point, it will raise an error.


primes.rs:14:17: 14:25 warning: value assigned to `is_prime` is never read, #[warn(unused_assignments)] on by default
primes.rs:14                 is_prime = 1;
                             ^~~~~~~~

That warning comes from this block:

if n < 4 {
    is_prime = 1;
}

This block is useless, because you are unconditionally setting is_prime to 1 after a couple of other if blocks, and you don't read back the variable between these assignments.


is_prime should be a boolean instead of an integer. Rust has a built-in boolean type, bool, and the keywords true and false, which you can use instead of 1 and 0.


Instead of having a mutable is_prime variable, I'd factor out the code that decides if a number is prime in a separate function. We can use early returns to avoid defining a mutable variable.

use std::io;

fn is_prime(n: u64) -> bool {
    if n < 4 {
        // Skip all the following checks, we know it's a prime!
        return true;
    }

    // We don't need to check if n is 2 or 3 anymore,
    // since if n is one of these values, we won't reach here.
    if n % 2 == 0 {
        return false;
    }

    if n % 3 == 0 {
        return false;
    }

    let mut m = 5;
    while m <= (n as f64).sqrt() as u64 {
        if n % m == 0 {
            return false;
        }

        if n % (m + 2) == 0 {
            return false;
        }

        m += 6;
    }

    // Implicit return
    true
}

fn main() {
    println!("Enter a number: ");
    let mut limit = String::new();
    io::stdin().read_line(&mut limit).expect("failed to read line");
    let limit: u64 = limit.trim().parse().expect("Please enter a number.");
    if limit <= 0 {
        println!("Number must be greater than or equal to 0.");
    } else {
        for n in 2..limit + 1 {
            if is_prime(n) {
                println!("{}", n);
            }
        }
    }
}
\$\endgroup\$
1
\$\begingroup\$

You could refactor your is_prime segment into a separate function and in a more functional style:

fn is_prime(n: u64) -> bool {

    if n < 4 { 
        return true; 
    }
    if n % 2 == 0 || n % 3 == 0 { 
        return false; 
    }

    (1u64..).map(|x| 6 * x - 1)
            .take_while(|x| (x * x) <= n)
            .all( |x| n % x != 0 && n % (x + 2)!= 0)
}

You can then iterate over all the primes like this:

for x in (1..limit + 1).filter(|x| is_prime(*x)) { 
    println!("{}", x);
}

Also a better approach would be to keep track of the previous prime numbers so you can test each number with just the primes less or equal than it's square root. Or even better use some of the algorithms mentioned here:

https://stackoverflow.com/questions/453793/which-is-the-fastest-algorithm-to-find-prime-numbers

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.