English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
집합(Collection)은 데이터 구조에서 가장 일반적인 데이터 저장 형식으로, Rust 표준 라이브러리는 개발자가 데이터 구조 작업을 처리하는 데 도움이 되는 다양한 집합 타입을 제공합니다。
벡터(Vector)는 여러 값을 저장하는 단일 데이터 구조이며, 이 구조는 동일한 타입의 값을 메모리에서 선형으로 저장합니다。
벡터는 선형 표본이며, Rust에서는 Vec<T>로 표현됩니다。
벡터의 사용 방식은 목록(List)과 유사합니다. 이렇게 특정 타입의 벡터를 생성할 수 있습니다:
let vector: Vec<i32>= Vec::new(); // 타입이 i32 의 비어 있는 벡터 let vector = vec![1i 2i 4i 8]; // 배열로 벡터 생성
우리는 자주 연속적인 작업을 사용하지만, 추가와 스택의 push 작업은 본질적으로 같습니다. 따라서 벡터는 단일 요소를 추가하는 push 메서드 만을 사용합니다:
fn main() { let mut vector = vec![1i 2i 4i 8]; vector.push(16); vector.push(32); vector.push(64); println!("{:?}", vector); }
실행 결과:
[1i 2i 4i 8i 16i 32i 64]
append 메서드는 하나의 벡터를 다른 벡터의 끝에 추가하는 데 사용됩니다:
fn main() { let mut v1: Vec<i32>= vec![1i 2i 4i 8]; let mut v2: Vec<i32>= vec![16i 32i 64]; v1.append(&mut v2); println!("{:?}", v1); }
실행 결과:
[1i 2i 4i 8i 16i 32i 64]
get 메서드는 벡터에서 값을 꺼내는 데 사용됩니다:
fn main() { ,1i 2i 4i 8]; println!("{}", match v.get(0) { Some(value) => value.to_string(), None => "None".to_string() }); }
실행 결과:
1
벡터의 길이를 논리적으로 추론할 수 없기 때문에, get 메서드는 항상 값을 가져올 수 없는 것을 보장할 수 없으며, 따라서 get 메서드의 반환 값은 Option 열거형이며, 비어 있을 수 있습니다。
이는 안전한 값을 가져오는 방법이지만, 쓰기가 좀 복잡합니다. 값의 인덱스가 벡터 인덱스 범위를 벗어나지 않을 것이라면, 배열 값 문법을 사용할 수도 있습니다:
fn main() { println!("{}", i);1i 2i 4i 8]; println!("{}", v[1]); }
실행 결과:
2
하지만 우리가 v[4let v = vec![
for i in &v {
fn main() { println!("{}", i);10for i in &mut v { 32i 57]; 조회 과정에서 변수의 값을 변경해야 할 경우: let mut v = vec![ } }
실행 결과:
100 32 57
0,
fn main() { ,10for i in &mut v { 32i 57]; = *0; +문자열 5String 클래스(String)은 이까지 많이 사용되었으므로 많은 메서드가 독자에게 잘 알려져 있습니다. 이 장에서는 문자열 메서드와 UTF를 주로 소개합니다. } }
새 문자열:-8 let string = String::new();
기본 타입을 문자열로 변환:
let one =
정수를 문자열로
let float = 1let slice = "slice".to_string(); // . .to_string(); 1부동소수점 수를 문자열로3let slice = "slice".to_string(); // 문자열 슬라이싱을 문자열로 UTF를 포함 // 문자의 문자열:
let hello = String::from("السلام عليكم");-8 let hello = String::from("Dobrý den");
let hello = String::from("Hello"); let hello = String::from("שָׁלוֹם"); let hello = String::from("नमस्ते"); let hello = String::from("こんにちは"); let hello = String::from("안녕하세요"); let hello = String::from("你好"); let hello = String::from("Olá"); let hello = String::from("Здравствуйте"); let hello = String::from("Hola"); 문자열 연결: let mut s = String::from("run");
s.push_str("oob");
추가할 문자열 슬라이싱 s.push('!'); // 추가할 문자 사용하여 // 문자열 연결:
String::from("Hello, "); + =
let s1 String::from("world!"); let s2 = let s3 s1 + &s2;
=
let s1 = String::from("tic"); let s2 = String::from("tac"); let s3 = String::from("toe"); 이 문법은 문자열 슬라이싱을 포함할 수도 있습니다:1 + "-" + &s2 + "-" + &s3;
format! 맥로를 사용하여:
let s1 = String::from("tic"); let s2 = String::from("tac"); let s3 = String::from("toe"); let s = format!("{}-{}-{}", s1, s2, s3);
문자열 길이:
let s = "hello"; let len = s.len();
여기서 len의 값은 5。
let s = "你好"; let len = s.len();
여기서 len의 값은 6입니다. 중국어는 UTF-8 인코딩된 것이며, 각 문자의 길이는 3 바이트, 따라서 길이는6。하지만 Rust는 UTF-8 문자 객체가 있기 때문에, 문자 수를 계산하려면 문자열을 문자 집합으로 가져올 수 있습니다:
let s = "hello你好"; let len = s.chars().count();
여기서 len의 값은 7총 7 개 문자. 문자의 개수를 세는 속도는 길이를 측정하는 속도보다 느립니다.
문자열을 탐색합니다:
fn main() { let s = String::from("hello中文"); for c in s.chars() { println!("{}", c); } }
실행 결과:
h e l l o 중 문
문자열에서 단일 문자를 꺼내기 위해:
fn main() { let s = String::from("EN中文"); let a = s.chars().nth(2); println!("{:?}", a); }
실행 결과:
Some('中')
주의nth 함수는 이터레이터에서 특정 값을 꺼내는 방법입니다. 이렇게 사용하지 마세요! لأن UTF-8 각 문자의 길이는 일치하지 않습니다!
문자열 부분을 잘라내고 싶다면:
fn main() { let s = String::from("EN中文"); let sub = &s[0..2]; println!("{}", sub); }
실행 결과:
EN
하지만 이 사용 방법이 UTF를 끊어서 나누는 가능성이 있습니다-8 그런 문자를 사용하면 오류가 발생할 수 있습니다:
fn main() { let s = String::from("EN中文"); let sub = &s[0..3]; println!("{}", sub); }
실행 결과:
thread 'main'에서 'byte index'에서 패닉했습니다 3 은 문자 경계가 아닙니다; '中' 내부에 있습니다 (바이트) 2..5) of `EN中文`', src\libcore\str\mod.rs:2069:5 주의: `RUST_BACKTRACE=`와 함께 실행하세요1환경 변수를 통해 백트레이스를 표시하려면 ` environment variable to display a backtrace.
지도표(Map)는 다른 언어에서 널리 존재합니다. 그 중 가장 일반적으로 사용되는 것은 키-값 해시 맵(Hash Map)입니다.
새로운 해시 값 매핑 테이블을 만듭니다:
use std::collections::HashMap; fn main() { let mut map = HashMap::new(); map.insert("color", "red"); map.insert("size", "10 m^2"); println!("{}", map.get("color").unwrap()); }
주의:해시 테이블의 일반화를 선언하지 않은 이유는 Rust의 자동 타입 추론 기계 때문입니다.
실행 결과:
red
insert 메서드와 get 메서드는 매핑 테이블에서 가장 많이 사용되는 두 가지 메서드입니다.
매핑 테이블은 이터레이터를 지원합니다:
use std::collections::HashMap; fn main() { let mut map = HashMap::new(); map.insert("color", "red"); map.insert("size", "10 m^2"); for p in map.iter() { println!("{:?}", p); } }
실행 결과:
("color", "red") ("size", "10 m^2)
요소를 순회하는 것은 키-값 쌍을 나타내는 튜플입니다.
Rust의 매핑 테이블은 매우 편리한 데이터 구조입니다. insert 메서드를 사용하여 새로운 키-값 쌍을 추가할 때, 동일한 키가 이미 존재하면 해당 값을 직접 덮어씁니다. "안전하게 추가"하려면, 현재 해당 키가 존재하지 않을 때만 추가하는 동작을 수행하려면 다음과 같이 할 수 있습니다:
map.entry("color").or_insert("red");
이 문장의 의미는 "color" 키가 존재하지 않으면 추가하고 값을 "red"로 설정하면 안되며, 존재하면 건너뜀을 의미합니다.
키가 이미 확정되어 있다면 해당 값을 직접 수정하려면 더 빠른 방법이 있습니다:
use std::collections::HashMap; fn main() { let mut map = HashMap::new(); map.insert(1, "a"); if let Some(x) = map.get_mut(&1) { *x = "b"; } }