프로그래밍과 잡담

Rust로 링크드리스트 만들어보기.. 본문

프로그래밍

Rust로 링크드리스트 만들어보기..

크레온 2019. 10. 3. 12:25

Rust 언어라고 있는데 최근에 나온 재미난 프로그래밍 언어이다.

모질라가 파이어폭스를 쓰고 있는데, 그 코드 중에 대부분이 C++이겠지..

근데 이 C++이 지랄같은게, 포인터를 사용하면서 각종 패러다임을 사용하는 언어라는거지. 게다가 사람은 실수 하게 마련이고, 그 실수는 메모리릭을 일으킬 수 있고, free 한고 free하는 문제도 있고, free한 걸 사용하거나 등등등 포인터와 관련된 여러가지 상황이 일어나는 어려운 언어이다. 잘하는 사람은 졸라 잘하지만 못하는 사람은 졸라 못하는게 이 언어라서 제대로 만들기가 어렵다.  메모리릭은 뭐 그래 스마트포인터인가 지랄인가 사용하면 된다는데 결국은 사람이 조정해야함..

 

위에 대한 이유때문에 파폭에 메모리릭이 일어나고 있었던 모양임.

그래서 그걸 해결하기 위해서 나온게 Rust 라는 언어이다. 모질라에 있던 직원이 시작하고 여러 사람들이 참여해서 만든 언어다.

 

요즘들어서 꽤나 관심을 갖고 있는 언어다.

 

이 언어의 특징은 신기한 특징을 가지고 있는데, 한 놈만 메모리를 점유하고 다른 놈이 동시에 쓸려고 하면 컴파일 단에서 에러가 발생한다.  즉, 다른놈이 쓰고 싶으면 복사해서 쓰거나 하라는거지. 아니면 빌려 쓰거나..

즉, C#이나 자바, 파이썬같은 언어들 처럼 가비지컬렉션(Garbage Collection)을 사용하지 않는다.  컴파일 할 때 다 추적해서, 컴파일 할 때 오류가 발생함.  대신에 언어가 초보자가 배우기에는 조금 빡쎄다.  하지만 메모리 안전성이라는 큰 장점 때문에 여러 곳에서 사용 할려고 하는거 같음.

 

어쨌든 그냥 심심해서 단일 링크드 리스트를 만들어보았다. 물론 Rust에는 C언어처럼 처음부터 만들어야 하는 언어가 아님. 이미 리스트계열들이나 벡터 등등 여러가지가 있어 보임. 그리고 인기가 많다보니 관심있는 사람들이 많이 라이브러리를 추가 중이라 ...

 

https://crates.io/ 여기 들어가면 라이브러리 졸라 많음.

 

 

아래를 클릭하면 대충 만든 단일 링크드 리스트가 나온다.  귀찮아서 제네릭 안씀..

...더보기

// 막 짰음. 최적화따위는 안되어 있으므로 그냥 봐..

use std::ptr;
use std::boxed::Box;
/**
 *  노드 데이터
 */ 
#[derive(Clone)]
struct Node {
    value: i32
}

impl Node {
    fn clone(&self) -> Node {
        Node { value: self.value }
    }
}

struct LinkedList {
    count: i32,
    data : Node,
    next : *mut LinkedList,
}

impl LinkedList {

    fn new() -> LinkedList {

        return LinkedList { 
            count: 0,
            data: Node { value: -1 },
            next: ptr::null_mut()
        }
    }
    
    fn add(&mut self, item: i32) {
        let node = Node { value : item };

        // value에 값이 없는 경우
        if self.data.value == -1 {
            self.data = node;
        } else {
            // 박스로 만들어야 추가될 때 값이 틀어지지 않음. Box로 안하면 기존의 값이 틀어지는 현상 있음.. 이상하게도.
            let mut new_list =  Box::new(LinkedList::new());;
            new_list.add(item);
         
            // 다음 노드
            let mut next_node = self.next;
            // 이전 노드는 일단 없으니까.. null 처리
            let mut prev: *mut LinkedList = ptr::null_mut();

            loop {
                // 다음 노드가 null 이면 넣을 자리 찾은거..
                if next_node == ptr::null_mut() {
                    break;
                }
                else {
                    unsafe {
                        // 포인터 다 보니 unsafe 블락을 써야함. 
                        let next_list: &LinkedList = &*next_node;
                        // 다음 노드를 이전 노드로 셋팅하고 
                        prev = next_node;
                        // 현재 노드는 그 다음 노드로 셋팅 
                        next_node = next_list.next;
                    }
                }

            }

            // null 인지 체크해서...뭐 사실 null이 나올 수 밖에 없지만 혹시 모르니..
            if next_node == ptr::null_mut() {
                
                // 이전 노드가 존재하면, 이전 노드의 다음노드에 값을 셋팅
                if prev != ptr::null_mut(){
                    unsafe {
                        let mut tmp = &mut (*prev); // *mut LinkedList 를 LinkedList로 변환
                        tmp.next = Box::into_raw(new_list);  // 그리고 이곳이 중요함. box를 raw로 변환해서 셋팅 안하면 그 다음거 추가할 때 틀어지는 현상 일어남..
                    }
                }else{
                    // 이전 노드가 없다면 루트 노드니까 바로 셋팅
                    self.next =  Box::into_raw(new_list);
                }

            } else {
                panic!("next_node는 반듯이 null 이어야 함!!");
            }
        }

        self.count = self.count + 1;
    } 

    fn get_value(&mut self, pos: i32) -> Node {
        
        let mut value: *const LinkedList = self.next;
        let mut result: Node = self.data.clone();

        if pos == 0 {
            return result;
        }

        for i in 1..self.count {
            if i == pos {
                unsafe {
                    let tmp = &*value;
                    result = tmp.data.clone();
                }
                break;
            } else {
                unsafe {
                    let tmp = &*value;
                    let next = tmp.next;
                    value = next;
                }
            }
        }

        return result.clone();
    }

}


fn main() {
    let mut list = LinkedList::new();
    list.add(10);
    list.add(20);
    list.add(30);
    list.add(40);
    
    let value1 = list.get_value(0);
    let value2 = list.get_value(1);
    let value3 = list.get_value(2);
    let value4 = list.get_value(3);
    

    assert_eq!(value1.value, 10);
    assert_eq!(value2.value, 20);
    assert_eq!(value3.value, 30 );
    assert_eq!(value4.value, 40 );

    println!(" value1 : {}, value2: {}", value1.value, value2.value);

}




반응형
Comments