'러스트 박살내기(?)' 시리즈Rust-Lang으로 알고리즘 문제 풀기 (K번째 소수)

배진오

@baealex

소비적인 일보단 생산적인 일을 좋아합니다.

저번에는 기초적인 문제로 기초적인 문법을 다뤘으니 이번엔 파이썬으로 작성한 코드중에 뭔가를 러스트로 변환해 보고자 하였다. 2가지 정도를 변환해 볼 것인데 이번에는 백준에서 무려 25점을 받았던 (...)


"개발자 능력 실화?"


K번째 소수라는 문제의 파이썬 코드를 러스트로 변환해 볼 것이다. 이 코드를 변환하는 이유는 필자의 궁금증을 해결하기 위함이다. 파이썬이기 때문에 25점을 받은건지, 아니면 내가 똥멍청인지. 일단 이 코드는 파이썬의 내부 함수가 아닌 기초적인 로직들이 들어있으므로 "기초 다지기 - 2" 정도의 포스트가 될 것이다.


K 번째 소수 — 파이썬

import math

def prime_of_number(K):
    if K == 0:
        return None
    prime_lists = list()
    counter = 0
    x = 2
    while True:
        is_prime = True
        for y in prime_lists:
            if y > math.sqrt(x):
                break
            if x % y == 0:
                is_prime = False
                break
        if is_prime:
            prime_lists.append(x)
            counter += 1
            if counter >= K:
                return prime_lists[counter - 1]
        x += 1

if __name__=='__main__':
    print(prime_of_number(int(input())))

위 코드를 고대로 러스트로 변경해 볼 것이다. 처음엔 코드가 술술 작성되서 "오? 역시 난 천재였나?" 싶었으나 온갖 오류가 발생하여 고치느라 진땀을 흘렸다. 발생했던 오류들과 해결하는 방법을 아래에 작성하였다.


cannot infer type for type parameter `T`
  • 벡터에 타입이 존재하지 않는다는 에러로 이전 포스트에서 '상근날드'라는 문제를 풀이할 때는 벡터의 형태를 지정하지 않아서 이번에도 똑같이 했더니 발생한 오류다. 벡터를 선언할 때 let mut m_vec: Vec<T> = Vec::new()로 하면 해결된다.


no method named `sqrt` found for type `i32` in the current scope
  • 구글에 검색하였더니 var.sqrt()로 제곱근을 구하길래 똑같이 따라했더니 발생한 오류였는데 i32에는 sqrt()라는 함수가 존재하지 않는다. 따라서 실수로 형태를 변환하고 제곱근을 구하였다. 그리고 실수와 정수를 비교할 수 없다는 오류도 있었는데... 러스트가 정적 타입의 언어라는 걸 자꾸 망각하는 듯 하다. 비교되는 값도 실수형으로 변환하고 값을 비교해 주었다. 형변환은 무조건 parsematch를 써야하는 줄 알았는데 var as Type으로 변환이 가능했다. 나중에 더 알아봐야 할 듯.


value moved here, in previous iteration of loop
  • 벡터를 반복문의 iterator로 넣었더니 발생한 오류였다. for문에 들어가는 벡터의 이름앞에 &를 표시하는 것으로 오류를 해결하였다.


cannot cast `&i32` as `f32`
  • for문의 iterator로 들어온 y라는 변수가 &i32라서 f32로 형변환이 안된다는 오류로 여러 게시글을 찾아보다가 C언어와 마찬가지로 *&를 교차하는 방식으로 사용하길래 이걸 힌트로 해결할 수 있었다. 다만 러스트에서 *&가 무엇을 의미하는지 잘 모르겠다. 메모리에 접근하려면 unsafe라는 키워드를 사용한다는 것으로 알고 있어서 메모리 관련된 건 아니라 생각했는데... 찾아봐야 할 것 같다.


K 번째 소수 — 러스트

use std::io;

fn input_int() -> i32 {
    let mut temp_str = String::new();
    io::stdin().read_line(&mut temp_str)
        .expect("Falied to read line");
    let result = match temp_str.trim().parse::<i32>() {
        Ok(i) => i,
        Err(_e) => {
            -1
        }
    };
    return result;
}

fn prime_of_number(_k: i32) -> i32 {
    if _k == 0 {
        return 0;
    }
    let mut prime_lists: Vec<i32> = Vec::new();
    let mut counter: i32 = 0;
    let mut x: i32 = 2;
    loop {
        let mut is_prime = true;
        for y in &prime_lists {
            let f_x = x as f32;
            let f_y = *y as f32;
            if f_y > f_x.sqrt() {
                break;
            }
            if x % y == 0 {
                is_prime = false;
                break;
            }
        }
        if is_prime {
            prime_lists.push(x);
            counter += 1;
            if counter >= _k {
                return prime_lists[prime_lists.len() - 1];
            }
        }
        x += 1;
    }
}

fn main() {
    println!("{}", prime_of_number(input_int()));
}

결과값 비교해보려고 파이썬과 러스트를 교차해서 실행했는데 파이썬에 값을 넣고 엔터를 치고 이후 러스트에 값 넣고 엔터를 쳤더니 러스트에서 결과가 먼저 나오는 걸 보고 굉장히 신기했다. 이대로라면 50점은 넘게 나오지 않을까!

예상외로 100점이 나와버렸다. 나는 똥멍청이가 아니었다!

😥 작성된 댓글이 없습니다!
댓글을 작성하기 위해 로그인이 필요합니다.