Vec의 memory layout을 보면 다음과 같다.
let mut numbers = Vec::with_capacity(3);
numbers.push(1);
numbers.push(2);
+---------+--------+----------+
Stack | pointer | length | capacity |
| | | 2 | 3 |
+--|------+--------+----------+
|
|
v
+---+---+---+
Heap: | 1 | 2 | ? |
+---+---+---+
우리는 String이 Vec<u8>로 표현된다는 것을 언급했다.
그럼 Vec에 대한 &str과 동일한 것은 무엇일까?
[T]는 type T의 elements의 연속적인 sequence의 slice다.
그리고 대부분 borrowed form인 &[T]로 쓰인다.
Vec의 slice reference를 만드는 방법은 다양하다.
let numbers = vec![1, 2, 3];
// Via index syntax
let slice: &[i32] = &numbers[..];
// Via a method
let slice: &[i32] = numbers.as_slice();
// Or for a subset of the elements
let slice: &[i32] = &numbers[1..];
Vec는 [T]를 target type으로 사용하여 Deref trait을 implement한다.
이 deref coercion 덕분에 Vec에 slice methods를 직접적으로 사용할 수 있는 것이다.
let numbers = vec![1, 2, 3];
// Surprise, surprise: `iter` is not a method on `Vec`!
// It's a method on `&[T]`, but you can call it on a `Vec`
// thanks to deref coercion.
let sum: i32 = numbers.iter().sum();
&[T]는 &str과 같이 fat pointer다.
그것은 slice의 첫번째 element의 pointer와 slice의 길이로 구성되어 있다.
만약 당신이 Vec에 3개의 elements를 가지고 있다면
let numbers = vec![1, 2, 3];
그리고 slice reference를 만든다면
let slice: &[i32] = &numbers[1..];
다음과 같은 memory layout을 볼 수 있다.
numbers slice
+---------+--------+----------+ +---------+--------+
Stack | pointer | length | capacity | | pointer | length |
| | | 3 | 4 | | | | 2 |
+----|----+--------+----------+ +----|----+--------+
| |
| |
v |
+---+---+---+---+ |
Heap: | 1 | 2 | 3 | ? | |
+---+---+---+---+ |
^ |
| |
+--------------------------------+
function에 Vec의 immutable reference를 pass할 때, &Vec<T>보다 &[T]를 선호해라.
이는 function이 반드시 Vec에 의해 지원되는 slice가 아닌 어느 종류의 slice라도 수용할 수 있게 해준다.
예를 들어, 당신은 Vec의 elements의 subset을 넘길 수 있다.
하지만 그 이상으로 array의 slice 또한 넘길 수 있다.
let array = [1, 2, 3];
let slice: &[i32] = &array;
Array의 slice와 Vec의 slice는 같은 type이다.
그들은 elements의 연속적인 sequence에 대한 fat pointer다.
Array의 경우에, heap이 아닌 stack을 point을 하는 것 뿐이고,
slice를 사용할 때, 전혀 문제가 되지 않는다.
10_slices exercise는 Vec slice의 모든 원소의 합을 return하는 function을 작성하는 것이었다.

그냥 쉽게 구현했다.
매번 str과 [T]와 같은 slice types에 대해 말할 때마다,
&str과 &[T]의 inmutable borrow form을 사용했다.
하지만 slices는 mutable할 수 있다.
mutable slice를 만드는 법이다.
let mut numbers = vec![1, 2, 3];
let slice: &mut [i32] = &mut numbers;
slice내의 elements를 수정할 수 있다.
slice[0] = 42;
이것은 Vec의 첫번째 element를 42로 바꿀 것이다.
immutable borrows를 다룰 때, 아래를 추천한다.
&Vec<T>와 같은 owned type의 references보다 &[T]와 같은 slice references를 선호해라.
하지만 mutable borrows의 경우에는 아니다.
다음 시나리오를 보자.
let mut numbers = Vec::with_capacity(2);
let mut slice: &mut [i32] = &mut numbers;
slice.push(1);
compile되지 않는다.
push는 slices의 method가 아니고 Vec의 method다.
이는 일반적인 원칙 중 하나로,
Rust는 slice로부터 elements를 추가하거나 제거할 수 없다.
그저 이미 있는 elements를 수정할 수 있다.
여기서 &mut Vec나 &mut String은 &mut [T]나 &mut str보다 더 엄격하다.
그냥 수행하는데 필요한 operations에 기반하여 가장 알맞은 type을 선택해라.
11_mutable_slices의 exercise는 내용이 3주전에 바뀌어서 버전문제로 진행하지 못하고 넘어가겠다.
아니 진행할거다. 언제? 내일.
위처럼 임시저장 해놓고 10월 2일인 지금 진행한다.
Rust로 PS를 여럿 해봤는데 상당히 쉽지 않다.
지금부터는 간략하게 보고 Embedded쪽 Rust를 살펴볼 생각이다.
일단 하던 exercise를 진행하겠다.

mutable slices와 pow를 이용해 쉽게 구현했다.
우리의 Ticket에는 유일하게 구별가능한 ID가 필요하다.
Ticket을 만들지 전까지는 ID를 모르고, Option으로 관리하기에는 None case에 대한 처리를 매번 해야한다.
그래서 이럴 때, states를 활용하는 것이다.
pub struct TicketDraft {
pub title: TicketTitle,
pub description: TicketDescription
}
pub struct Ticket {
pub id: TicketId,
pub title: TicketTitle,
pub description: TicketDescription,
pub status: Status
}
위와 같이, 두개의 분리된 types로 표현된다.
TicketDraft는 아직 생성되지 않은 ticket이며, id와 status가 없다.
Ticket은 생성된 ticket이며, id와 status가 있다.
12_two_states exercise는 시간 걸려서 어찌저찌 했다.
add_ticket 부분에서 Ticket 구조체를 새로 만들고 그것을 tickets vec에 넣어줬다.
그리고 ticket의 id는 tickets vec의 index로 했다.
또한 get method를 구현했는데 id의 유효성 검사를 하며,
유효하지 않으면 Option type의 None,
유효하면 Some으로 Ticket 객체를 return한다.

뭐.. 잘했다.
오랜만에 Rust를 했는데, 중간에 버벅거리는 부분이 있었지만
검색을 통해, 쉽게 해결할 수 있었다.
현재 임베디드 시스템 설계라는 과목을 듣고 있는데
그와 관련하여 Rust로 회로를 다뤄보는 것을 하고 싶다.
'Rust Programming' 카테고리의 다른 글
| [Rust] 6. HashMap, BTreeMap (0) | 2024.10.07 |
|---|---|
| [Rust] 6. Index trait, IndexMut trait (0) | 2024.10.06 |
| [Rust] 6. Ticket Management: Combinators, impl Trait (0) | 2024.08.09 |
| [Rust] 6. Ticket Management: Iterators, Iter, Lifetimes (0) | 2024.08.07 |
| [Rust] 6. Ticket Management: Arrays, Vectors, Resizing (0) | 2024.08.07 |