[1. 개요]
- 러스트 표준 라이브러리에 포함된 컬렉션이라 불리는 데이터 구조가 있다.
- 이 들은 내장된 배열 및 튜플과 달리 heap 에 저장된다.
- 즉, 데이터 양이 컴파일 타임에 결정되지 않아도 된다.
- 아래와 같은 타입이 있다.
1. Vector
2. String
3. HashMap
[2. 벡터, (Vec)]
- 벡터를 생성하는 여러가지 방법
1. let v: Vec<i32> = Vec::new();
=> vector 에 저장 할 타입에 대한 명시가 필요하다.
2. let v = vec![1, 2, 3];
=> vec! 매크로를 사용하여 생성하는 방법
=> i32 타입을 추론 할 수 있으므로, 타입 명시가 필수가 아니다. - push 메소드
=> vector 에 새로운 element 를 추가한다.
=> mut vector 에 대해서만 동작한다. - 데이터 접근 방법
1. [] 를 사용하는 방법
=> 인덱스로 접근 하는 방법
=> 값을 반환한다.
=> 경계 검사를 하지 않으므로 무효한 인덱스인 경우 panic 이 발생한다.
2. get() 메소드를 사용하는 방법
=> Option<&T> 를 반환한다.
=> 무효한 인덱스인 경우 panic 이 발생하지 않는다. - 유효하지 않은 참조자 예시
=> 벡터에 새로운 element push 시, 내부 용량이 충분하지 않은 경우
새로운 배열 생성 및 복사 후 push 하므로
이전에 선언 된 벡터 내부 데이터에 대한 참조자는 무효하게 되어 컴파일 에러가 발생한다. - 반복처리
- 열거형을 사용한 여러 타입 저장
1. 벡터 내 다른 타입의 값들을 저장할 필요가 있다면 열거형을 정의하여 사용할 수 있다.
2. 러스트가 컴파일 시점에 벡터 내 저장될 타입이 어떤 것인지 알아야 할 필요가 있는 이유는
각 요소를 저장하기 위해 필요한 힙 메모리 크기를 알기 위함이다.
3. trait 객체 역시 벡터에 저장 할 수 있다. (이후에 자세히)
[3. String]
Rust 에서 string 은 바이트의 컬렉션 및 이 바이트들을 텍스트로 변환 할 떄
유용한 기능을 제공하는 몇몇 메소드로 구현되어 있다.
String 타입은 표준 라이브러리를 통해 제공되며,
가변적이고, 소유권을 갖고 UTF-8 로 인코딩 된다.
표준 라이브러리는 OsString, OsStr, CString, CStr 과 같은 다른 스트링 타입도 제공한다.
- String 생성하기
1. let mut s = String::new();
=> 비어있는 string 생성
=> 비어있기 때문에, 이후 데이터 변경을 위해 mut 를 사용하는 것이 보편적
2. 리터럴 스트링에서 to_string() 호출
=> 아래 String::from() 과 완전히 동일한 기능을 수행
3. let s = String::from("initial contents");
=> - String 갱신하기
1. push_str()
=> 인자로 전달 한 문자열을 끝에 추가한다.
=> 리터럴 문자열이 아닌 것을 전달 할 때는, 참조자로 전달하도록 한다.
2. push()
=> 한개의 문자를 파라미터로 받아서 기존 String에 추가한다.
3. 연산자 +
=> fn add(self, s: &str) -> String 과 같은 방식으로 동작함
=> s1 에 대한 소유권이 이전되므로, s1 은 이후 유효하지 않다.
4. format!
=> format! 매크로는 println! 와 똑같은 방식으로 동작
=> 그 어떤 파라미터들의 소유권도 가져가지 않는다. - String 내부 인덱싱
=> 일반적으로 [] 을 이용한 string 내부 데이터 접근은 허용되지 않는다.
=> String 은 Vec<u8> 을 wrapping 하여 구현되어있기 때문
=> UTF-8 인코딩을 하므로, 문자 하나가 1바이트를 점유 한다고 할 수 없다.
=> 러스트 관점에서 문자열을 보는 세가지 의미있는 방식
1. 바이트
2. 스칼라 값
3. 문자소 클라스터 (사람 입장에서 문자라 할 수 있는 것) - String Slice
=> 스트링 슬라이스를 만들기 위하여 범위를 이용하는 방법은 항상 조심스러워야 한다.
=> 문자 처리 방식 때문에... - String 반복문
1. chars() 메소드
=> 개별적인 유니코드 스칼라 값에 대한 연산을 수행하고 싶은 경우 사용
2. bytes() 메소드
=> 가공하지 않은 각각의 바이트를 반환한다.
[4. HashMap]
HashMap<K, V> 형태
내부 해쉬 함수를 사용해서 K 와 V 를 매핑한다.
- 해쉬맵 생성
use 를 사용하여 HashMap 을 scope 내로 가져와야 한다.
Vector 와 String 보다 덜 사용되어, 자동으로 가져오지 않는다.
또, vec! 처럼 해쉬맵 생성을 위한 내장된 매크로가 없다.
혹은 위와 같이 길이가 같은 vector 에 대해서 k, v 로 갖는 HashMap 을 생성할 수 있다.
이 경우, vector 로 부터 타입을 추론 할 수 있으므로,
HashMap 에 대한 타입은 생략할 수 있다. - 소유권
Copy trait 을 구현한 타입은 HashMap 안으로 복사되며,
String 과 같은 값들을 소유권이 이전된다. - 해쉬맵 내 값 접근
- 갱신
- 값 덮어쓰기 (key 가 이미 있는 경우)
=> insert() 메소드 - key 가 없는 경우 삽입하기
=> entry() 메소드
==> key 를 파라미터로 전달, 열거형 Entry 를 반환
===> or_insert() 메소드, key 가 존재할 경우 값을 반환하고, 없는 경우 key에 대한 값으로 삽입하고
수정 된 Entry() 를 반환 - 이전 값을 기초로 값 갱신
- 값 덮어쓰기 (key 가 이미 있는 경우)
- 해쉬 함수
HashMap 은 Dos 공격에 저항할 수 있는 기능을 제공하는 보안 해쉬 함수를 사용
BuildHasher trait 을 구현하여 해쉬 함수를 변경 할 수 있다.
'Rust > 개념' 카테고리의 다른 글
Rust. 에러 처리 (0) | 2022.08.29 |
---|