티스토리 뷰

Rust-Language

collection - vector

kmj24 2021. 4. 23. 21:34

vector

Vec<T>(vector)에 대하여 알아보자

vector는 memory상 서로 이웃하도록 모든 값을 집어넣는 단일 데이터 구조이며 하나 이상의 값을 저장할 수 있도록 해준다. vector는 같은 타입의 값만 저장가능하다.

vector를 선언하는 방법

let v : Vec<i32> = Vec::new();

위의 코드에서 vector를 선언할 때, 아무런 값도 할당도 하지 않았기 때문에, rust는 저장하고자 하는 요소의 type이 어떤 것인지 알지 못한다. vector는 제너릭을 이용하여 구현되었고 어떠한 값을 할당하지 않고 선언할 때는 제너릭 내에 type을 작성해주면 된다. 

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

vector에 값을 push하고싶은 경우 다음과 같이 사용할 수 있다.

let mut v = vec![1, 2, 3];
v.push(5);
v.push(6);
v.push(7);

vector는 스코프 밖으로 벗어날 경우 해제된다.

{
   let mut v = vec![1, 2, 3];
   println!("{:?}", v);
   v.push(5);
   v.push(6);
   v.push(7);
} //=> 요기서 해제

vector요소 읽기

vector내 저장한 값을 참조하는 방법

1. 인덱스 문법 사용

    let third : &i32 = &v[2];
    println!("{}", third);

2. get method 사용

let third : Option<&i32> = v.get(2);
println!("{:?}", third);
//output : Some(3)

get method를 사용하는 방법은 get함수에 참조하고자 하는 index를 argument로 넘겨 Option<&T>를 얻은것이다.

rust가 이와 같이 vector의 요소를 참조하는 두가지 방법을 제공하는 이유는 vector가 가지고 있지 않은 인덱스의 원소에 접근하려고 헀을 경우에 대한 safe를 위함이다.

    let v : Vec<i32> = vec![1, 2, 3, 4];
    println!("{}", &v[4]);

위의 코드에서 vector v에 있지 않는 4번째 원소에 접근할 때 프로그램이 뻗어버린다.

위와 같은 상황을 방지하기 위해 아래의 코드와 같이 사용할 수 있다.

let v : Vec<i32> = vec![1, 2, 3, 4];
println!("{:?}", v.get(4));
//output => None

위의 코드는 None을 반환한다.

vector의 원소 밖을 탐색하게 될 수있는 상황이 종종 발생할 경우 위와 같이 사용하는 것이 좋다.

유효하지 않은 참조자

프로그램이 유효한 참조자를 얻을 때, 빌림 검사기(borrow checker)가 소유권 및 빌림 규칙을 적용하여, 이 참조자와 vector의 내용물로부터 얻은 다른 참조자들이 계속 유효하게 남아있도록 확실히 해준다. (하나의 스코프 내 가변 참조자와 불변 참조자를 가질 수 없는 규칙)

아래의 코드를 실행시켜보자.

let mut v = vec![1, 2, 3, 4, 5];
let first = &v[0];
v.push(6);
println!("{}", first);

그렇다면 다음과 같은 오류를 만날것이다.

참조자를 가지는 동한 vector에 push를 시도할 경우 오류가 발생한다.

첫번째 원소를 참조하고있지만 마지막 요소를 추가하는 경우 오류가 발생하는 이유는, vector의 동작 방법때문이다.

새로 메모리를 할당하여 이전 요소를 새 공간에 복사할 경우가 있을 수 있는데, 이에 대하여 vector가 모든 요소들을 붙여 저장할 공간이 충분하지 않는 환경에서 일어날 수도 있다.

 

그렇게 될 경우 첫번째 요소에 대한 참조자는 해제된 메모리를 가리키게 될 것이다.(댕글링 참조자가 될 가능성이 있다.)

위 사진은 길이가 2인 vector가 있고 첫번째 원소를 참조하는 참조자가 있을 경우이다.

해당 vector에 push를 할 경우 현재의 메모리에서 연속된 값으로 할당할 수 있는 공간이 없으므로,

공간이 vector를 memory상 연속으로 위치할 수 있는 곳으로 이동한다.

이 경우 댕글링 참조자가 발생한다.

vector 원소 반복문

let mut v = vec![1, 2, 3, 4, 5];
for i in 0 .. v.len(){
   println!("{}", &v[i]);
}
print!("\n");
for i in &v{
   println!{"{}", i};
}

반복문을 이용하여 vector내 원소를 가변적으로 바꿀 수 있다.

let mut v = vec![2, 4, 8];
for i in &mut v{
   *i += 10;
   println!("{}", i);
}

열거형을 사용하여 여러타입 지정

vector를 하나의 타입으로만 저장할 수 있다고 했는데, 다른 타입을 각각 사용할 필요가 있을 경우 열거형을 사용하여 해결할 수 있다.

#[derive(Debug)]
enum SpreadsheetCell{
    Int(i32),
    Float(f64),
    Text(String)
}

fn each_type(){
    let row = vec![
        SpreadsheetCell::Int(3),
        SpreadsheetCell::Text(String::from("blue")),
        SpreadsheetCell::Float(10.15)
    ];
    for i in &row{
        println!("{:?}", i);
    }
}

rust가 컴파일 단계에서 vector 내 저장될 type이 어떤 것인지 알아야 할 필요가 있는 이유

 - 각 요소를 저장하기 위해 얼마만큼의 heap메모리가 필요한지 알기 위함이다.

 - vector에 허용되는 type에 대해 명시적으로 작성

 

만약 프로그램을 작성할 때 런타임에 vector에 저장할 type의 모든 경우를 특정할 수 없다면 trait객체를 이용해야 되며,

trait에 대해서는 추후 알아보자.

 

전체 코드

pub fn run(){
    let mut v : Vec<i32> = Vec::new();
    println!("{:?}", v);
    {
        let mut v = vec![1, 2, 3];
        v.push(5);
        v.push(6);
        v.push(7);
        println!("{:?}", v);
    }
    v.push(1);
    v.push(2);
    v.push(3);
    println!("{:?}", v);

    let third : &i32 = &v[2];
    println!("{}", third);
    let third : Option<&i32> = v.get(2);
    println!("{:?}", third);

    let v : Vec<i32> = vec![1, 2, 3, 4];
    //println!("{}", &v[4]);
    println!("{:?}", v.get(4));

    let mut v = vec![1, 2, 3, 4, 5];
    //let first = &v[0];
    //v.push(6);
    //println!("{}", first);
    _loop(&v);
}

fn _loop(v : &Vec<i32>){
    print!("\n");
    for i in 0 .. v.len(){
        println!("{}", &v[i]);
    }
    print!("\n");
    for i in v{
        println!{"{}", i};
    }
    print!("\n");
    let mut v = vec![2, 4, 8];
    for i in &mut v{
        *i += 10;
        println!("{}", i);
    }
    print!("\n");
    each_type();
}

#[derive(Debug)]
enum SpreadsheetCell{
    Int(i32),
    Float(f64),
    Text(String)
}

fn each_type(){
    let row = vec![
        SpreadsheetCell::Int(3),
        SpreadsheetCell::Text(String::from("blue")),
        SpreadsheetCell::Float(10.15)
    ];
    for i in &row{
        println!("{:?}", i);
    }
}

 

참고 : rinthel.github.io/rust-lang-book-ko/ch08-01-vectors.html

 

벡터 - The Rust Programming Language

우리가 보게될 첫번째 콜렉션은 벡터라고도 알려진 Vec 입니다. 벡터는 메모리 상에 서로 이웃하도록 모든 값을 집어넣는 단일 데이터 구조 안에 하나 이상의 값을 저장하도록 해줍니다. 벡터는

rinthel.github.io

rust의 vector에 대한 표준 라이브러리

doc.rust-lang.org/std/vec/struct.Vec.html

 

std::vec::Vec - Rust

 

doc.rust-lang.org

 

'Rust-Language' 카테고리의 다른 글

Closure, 클로저 함수  (0) 2021.08.05
스마트 포인터  (0) 2021.05.16
if let 흐름 제어  (0) 2021.04.13
match 흐름 제어 연산자  (0) 2021.04.09
열거형  (0) 2021.04.09
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함