벡터



기본적인 컬렉션 타입 Vec<T>(이하 벡터) 에 대해 알아봄. 벡터는 std 에 포함된 컬렉션 타입임. 따로 스코프로 로드하지 않아도 사용할 수 있음. 한 벡터 인스턴스에는 오직 같은 타입의 값만 저장 가능함.



벡터 인스턴스 생성 방법


기본적인, 빈 벡터 인스턴스는 아래와 같이 생성. 제너릭에 타입을 지정함.


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


아래는 벡터 인스턴스 생성과 함께 초기값을 설정. 초기값의 타입에 따라 벡터의 제너릭 타입이 추론됨.


let v = vec![1, 2, 3];



벡터 변경


기본적으로 아래와 같이 벡터에 데이터를 넣음. 벡터에 값을 넣거나 빼려면 역시 뮤터블이어야 함


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

v.push(1);
v.push(2);
v.push(3);



러스트의 다른 인스턴스와 마찬가지로, 벡터 또한 스코프를 벗어나면 메모리에서 해제되며, 벡터가 가지고 있던 값들도 사라짐.


{
let v = vec![1, 2, 3];
// do something..
}



벡터의 요소 읽기


아래 코드에 벡터의 요소를 읽은 두 가지 다른 방법이 있음.


let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
let third: Option<&i32> = v.get(2);


첫 번째는 인덱스를 직접 접근, 두 번째는 get 메서드를 사용. 두 방법의 차이는 다음과 같음.


let v = vec![1, 2, 3, 4, 5];
let does_not_exist: &i32 = &v[100];
let does_not_exist: Option<&i32> = v.get(100);


위처럼 범위를 넘어선 인덱스를 지정하면 첫 번째 방법은 panic 이 발생함. 반면 두 번째 방법은 Option<T> 타입인 None 을 리턴하여, 해당 인덱스에 요소가 없을 경우에 실행할 코드를 지정할 수 있음. 인덱스에 요소가 없을 때 치명적인 오류로 보고 프로그램을 바로 종료한다면 첫 번째 방법을, 요소가 없는 경우가 발생할 수 있고 이에 대해 다른 대응을 해야 한다면 두 번째 방법을 취하면 됨.



무효한 레퍼런스


벡터의 요소를 읽는 데에도 레퍼런스 대여 규칙이 적용됨. 


let mut v = vec![1, 2, 3, 4, 5];

let first = &v[0]; // 임뮤터블 대여 발생

v.push(6); // 뮤터블 대여 발생

위 코드는 컴파일 에러를 일으킴.


벡터에 충분한 여유 공간이 없다면, 벡터에 새로운 값을 넣는 push 메서드는 새로운 메모리 할당을 요구하고 기존 요소를 새로운 공간에 복사하는 작업을 수행할 수 있음. 그런데 위의 변수 first 가 벡터의 기존 첫 번째 요소(의 주소)를 참조하고 있는데 push 메서드로 인해 그 요소의 메모리가 해제되는 일이 생기면, 변수 first 의 참조는 무효한 것이 되어버림. 이런 현상을 방지하고자 컴파일러는 앞서 레퍼런스 대여 규칙을 체크함.



벡터 값 순회하기


아래는 기본적인 방법.


let v = vec![100, 32, 57];
for i in v {
println!("{}", i);
}



아래는 벡터 안의 요소값을 변경할 경우.


let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50;
}

각각의 값에 50을 더함.


'*' 는 역참조(디레퍼런스) 연산자임. 참조(&) 로 요소를 읽어왔기에, 안의 값을 변경하려면 다시 역참조를 수행.



enum 을 이용한 다양한 타입 다루기


벡터 인스턴스는 한번에 한 가지 타입으로 제한되기 때문에, 여러 타입을 하나의 벡터에 넣으려면 enum 을 사용하는 방법이 있음.


enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}

let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text("blut".to_string()),
SpreadsheetCell::Float(10.12),
];


러스트가 이렇게 벡터의 타입을 미리 지정하도록 하는 이유는, 벡터가 요소를 저장하는 데에 필요한 메모리를 컴파일 타임에 알 수 있게 하기 위함임. 그리고 벡터에 아무 타입이나 담을 수 있게 되면, 하나의 벡터 인스턴스를 다루면서 안에 섞여 있는 요소의 다양성으로 인해 오류가 발생할 위험성이 높아지기 마련임.


하지만 enum 은 완전하지 않음. 때로는 구현하려는 프로그램이 런타임에 어떤 타입의 데이터를 받게 될지 알 수 없는 경우가 있을 이럴 때 enum 은 유효하지 못함. 이럴 땐 '특성(트레잇)' 을 사용해야 하는데, 이건 나중에 다루기로 함.




'Rust' 카테고리의 다른 글

컬렉션(해시맵)  (0) 2018.02.25
컬렉션(스트링)  (0) 2018.02.24
모듈(다른 모듈 접근)  (0) 2018.02.22
모듈(pub)  (0) 2018.02.22
모듈  (0) 2018.02.22

+ Recent posts