벡터(vector) 타입
Rust에서 배열(array)은 동일한 타입의 요소를 갖는 고정된 길이의 배열(fixed array)이다. 배열과 같이 동일한 타입의 요소들을 갖지만, 그 길이를 신축적으로 늘릴 수 있는 것을 벡터(vector)라고 한다.
벡터 생성 및 초기화
벡터를 생성하기 위해서는 Vec 타입의 생성자 함수인 new()를 호출한다. 즉, Vec::new() 를 호출하여 빈 벡터를 생성한다. 벡터는 항상 동일한 타입이어야 하는데, Vec::new() 함수를 호출하는 것으로는 어떤 타입의 데이타가 저장되는지 알 수 없으며 또한 아래 예제의 경우 다른 추가적인 코드에서 벡터 타입을 따로 추론할 수도 없으므로, 아래 예제의 v1 변수에는 변수 타입(type annotation)을 지정해 주어야 한다.
fn main() { // create empty i32 vector let v1: Vec<i32> = Vec::new(); // create i32 vector with initial values let v2 = vec![1,2,3,4,5]; println!("{:?} {:?}", v1, v2); }
벡터를 생성할 때 만약 초기값을 함께 지정하고 싶으면, vec! 매크로를 사용할 수 있다. vec! 매크로는 초기값들을 가진 벡터를 생성하며, 여기에 새로운 요소를 추가하거나 수정할 수 있다. Vec::new()와 달리, vec! 매크로는 초기값들의 타입을 알 수 있으므로, 벡터의 변수 타입을 꼭 지정할 필요는 없다. 예를 들어, 위 예제에서 변수 v2는 vec! 매크로에 의해 1 ~ 5의 숫자를 가지므로, v2는 (정수의 디폴트 타입인) i32의 벡터 타입이 된다.
벡터 데이타 수정
벡터에 데이타를 추가하기 위해서는 push() 메서드를 사용한다. 벡터의 모든 요소를 출력하기 위해서는 "{:?}" 혹은 "{:#?}" 을 사용할 수 있다. 아래 예제에서 변수 v는 데이타가 수정되므로 mut 로 선언되었고, push() 메서드의 파라미터가 정수이므로 변수 v의 타입은 Vec<i32> 으로 자동 추론된다.
fn main() { let mut v = Vec::new(); v.push(1); v.push(2); println!("{:?}", v); }
벡터 데이타 읽기
벡터의 데이타를 읽는 방법으로는 (1) 벡터의 인덱스를 사용하거나 (2) 벡터의 get() 메서드를 사용하는 방법이 있다.
벡터의 인덱스를 사용하기 위해서는 벡터 변수에 레퍼런스를 취한 후 [ ] 안에 인덱스를 지정하면 된다. 예를 들어, 아래 예제에서 벡터 v의 두번째 요소를 읽기 위해서 &v[1] 과 같이 사용하였는데, 이는 벡터 v의 요소에 대해 Immutable Borrow를 한 것이다.
fn main() { let mut v = Vec::new(); v.push(1); v.push(2); v.push(3); println!("v: {:?}", v); // (1) 인덱스 사용하여 읽기 let n1 = &v[1]; println!("&v[1]: {}", n1); // (2) get() 메서드로 읽기 let elem1 = v.get(1); println!("v.get(1): {:?}", elem1) }
두번째 읽기 방법으로 벡터의 get() 메서드를 사용할 수 있는데, 위의 예제에서 벡터 v의 두번째 요소를 가져오기 위해 v.get(1)을 사용하였다. 이때의 리턴 타입은 Option<T> 으로 값이 없는 경우와 값이 있는 경우를 함께 리턴하게 된다. 예를 들어, v.get(10) 을 하게 되면 값이 없으므로 None이 리턴될 것이고, v.get(1)을 하면 값이 있는 경우로서 Some(2) 가 리턴될 것이다. 아래는 위 예제의 실행 결과를 표시한 것이다.
v: [1, 2, 3] &v[1]: 2 v.get(1): Some(2)
벡터 인덱스를 사용할 때 만약 벡터 길이의 밖의 인덱스를 주게 되면 프로그램이 Crash 될 것이다. 반면, get() 메서드의 경우 None을 리턴하여 값이 없는 경우에 어떻게 처리할 지를 지정할 수 있다.
벡터 Iterator
벡터의 요소를 모두 하나씩 가져와 읽거나 수정하기 위해서, for 루프와 결합하여 Iteration 을 사용할 수 있다. 예를 들어, 아래는 벡터 v의 요소들을 하나씩 읽어 출력하는 예제이다.
fn main() { let v = vec![1,2,3]; for n in &v { println!("{}", n); } }
벡터의 요소를 수정하기 위해서는 먼저 벡터 변수 v를 mut 로 선언하고, "&mut v" 와 같이 mutable reference를 만들어 for 루프 안에서 각 요소를 수정한다. 아래 예제는 벡터 v의 각 요소에 1을 더하여 값을 출력하는 예이다. 레퍼런스 n에 대해 Dereference 연산자인 *을 사용하여 n이 가리키는 장소의 값을 가져오고, 그 장소에 1이 추가된 값을 저장하게 한다.
fn main() { let mut v = vec![1,2,3]; for n in &mut v { *n = *n + 1; println!("{}", n); } }