본문 바로가기

Rust/개념

Rust. 컬렉션

[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 과 같은 값들을 소유권이 이전된다.

  • 해쉬맵 내 값 접근
  • 갱신
    1. 값 덮어쓰기 (key 가 이미 있는 경우)
      => insert() 메소드
    2. key 가 없는 경우 삽입하기
      => entry() 메소드
      ==> key 를 파라미터로 전달, 열거형 Entry 를 반환
      ===> or_insert() 메소드, key 가 존재할 경우 값을 반환하고, 없는 경우 key에 대한 값으로 삽입하고
                수정 된 Entry() 를 반환
    3. 이전 값을 기초로 값 갱신
  • 해쉬 함수
    HashMap 은 Dos 공격에 저항할 수 있는 기능을 제공하는 보안 해쉬 함수를 사용
    BuildHasher trait 을 구현하여 해쉬 함수를 변경 할 수 있다.

'Rust > 개념' 카테고리의 다른 글

Rust. 에러 처리  (0) 2022.08.29