컬렉션은 다수의 값을 담을 수 있음
Vec<T>
같은 타입의 값만을 저장할 수 있음
(어떠한 타입의 값이라도 저장 가능)파일 내의 텍스트 라인들
이나 장바구니의 품목 가격
같은 아이템 목록을 저장하는 상황일 때 유용 let v: Vec<i32> = Vec::new();
Vec<T>
를 생성하고, 러스트는 저장하고자 하는 값의 타입을 대부분 유추할 수 있으므로, 이런 타입 명시를 할 필요가 거의 없음vec! 매크로를 제공
: 제공된 값들을 저장한 새로운 Vec을 생성let v = vec![1, 2, 3];
let mut v = Vec::new();
v.push(5);
v.push(6);
v.push(7);
v.push(8);
Vec<i32>
타입 명시를 붙이지 않아도 되는 이유는, 집어넣은 숫자가 모두 i32 타입인 점을 통하여 러스트가 v의 타입을 추론하기 때문 let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
println!("The third element is {third}");
let third: Option<&i32> = v.get(2);
match third {
Some(third) => println!("The third element is {third}"),
None => println!("There is no third element."),
}
&와 []
를 사용하면 인덱스 값에 위치한 요소의 참조자를 얻게 됩니다. Option<&T>
를 얻게 됩니다. let mut v = vec![1, 2, 3, 4, 5];
let first = &v[0];
v.push(6);
println!("The first element is: {first}");
// error
// cannot borrow `v` as mutable because it is also borrowed as immutable
let v = vec![100, 32, 57];
for i in &v {
println!("{i}");
}
let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50;
}
* 역참조 연산자로 i의 값을 얻어야 합니다.
벡터 내에 다른 타입의 값들을 저장할 필요가 있다면 열거형을 정의하여 사용할 수 있습니다!
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
{
let v = vec![1, 2, 3, 4];
// v를 가지고 작업하기
} // <- 여기서 v가 스코프 밖으로 벗어나고 해제됩니다
&str
(문자열 슬라이스
)
문자열 슬라이스
: 문자열(String)의 일부분을 참조원본 문자열 데이터를 참조
문자열 타입은 오직 하나뿐
let slice = &s[0..3]
문자열 리터럴
(고정된 텍스트)let s = "Hello";
문자열이 컬렉션 장에 있는 이유는
문자열이 바이트의 컬렉션으로 구현
되어 있고, 이 바이트들을 텍스트로 통역할 때 유용한 기능을 제공하는 여러 메서드들을 구현
해 두었기 때문사람과 컴퓨터가 String 데이터를 통역하는 방식 간의 차이로 인해 생기는 String 인덱싱의 복잡함을 논의해 보자.
문자열 (String)
String은 str 데이터를 소유(포함)
let mut s = String::from("Hello");
s.push_str("How are you?");
let mut s = String::new();
to_string 메서드
를 이용하는데, 이는 Display 트레이트가 구현된 어떤 타입이든 사용 가능하며, 문자열 리터럴도 이 트레이트를 구현하고 있습니다. let data = "initial contents"; // 문자열 리터럴
let s = data.to_string();
// 이 메서드는 리터럴에서도 바로 작동합니다:
let s = "initial contents".to_string();
let s = String::from("initial contents");
+ 연산자
나 format! 매크로
를 사용하여 편리하게 String 값들을 이어붙일 수 있습니다. let mut s = String::from("foo");
s.push_str("bar");
let mut s1 = String::from("foo");
let s2 = "bar";
s1.push_str(s2);
println!("s2 is {s2}");
만일 push_str 함수가 s2의 소유권을 가져갔다면, 마지막 줄에서 이 값을 출력할 수 없었을 것입니다. 하지만 이 코드는 기대했던 대로 작동합니다!
push 메서드는 한 개의 글자를 매개변수로 받아서 String에 추가
let mut s = String::from("lo");
s.push('l');
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // s1은 여기로 이동되어 더 이상 사용할 수 없음을 주의하세요
+ 연산자
는 add 메서드를 사용하는데, 이 메서드의 시그니처는 아래처럼 생겼습니다:fn add(self, s: &str) -> String {
add가 제네릭과 연관 타입을 사용하여 정의되어 있음
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");
let s = s1 + "-" + &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 s1 = String::from("hello");
let h = s1[0];
// error[E0277]: the type `String` cannot be indexed by `{integer}`
Vec<u8>
을 감싼 것 let hello = String::from("Hola");
let hello = String::from("Здравствуйте");
let hello = "Здравствуйте";
let answer = &hello[0];
[224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164,
224, 165, 135]
['न', 'म', 'स', '्', 'त', 'े']
["न", "म", "स्", "ते"]
let hello = "Здравствуйте";
let s = &hello[0..4];
for c in "Зд".chars() {
println!("{c}");
}
З
д
다른 방법으로 bytes 메서드는 각 원시 바이트를 반환하는데, 문제의 도메인이 무엇인가에 따라 적절할 수도 있습니다:
for b in "Зд".bytes() {
println!("{b}");
}
위의 코드는 이 문자열을 구성하는 네 개의 바이트를 출력합니다:
208
151
208
180
K 타입의 키
와 V 타입의 값
에 대해 해시 함수 (hashing function) 를 사용하여 매핑한 것을 저장 use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
해시맵도 데이터를 힙에 저장
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
let team_name = String::from("Blue");
let score = scores.get(&team_name).copied().unwrap_or(0);
Option<&V>
를 반환Option<i32>
를 얻어온 다음, use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
for (key, value) in &scores {
println!("{key}: {value}");
}
Copy 트레이트를 구현한 타입의 값
은 해시맵 안으로 복사됨 use std::collections::HashMap;
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");
let mut map = HashMap::new();
map.insert(field_name, field_value);
// field_name과 field_value는 이 시점부터 유효하지 않습니다.
// 사용을 시도해보고 무슨 컴파일러 에러가 발생하는 알아보세요!
각각의 유일한 키는 연관된 값을 딱 하나만 가질 수 있습니다.
(그 역은 성립하지 않습니다: 예를 들면 블루 팀과 옐로 팀 모두 scores 해시맵에 10점을 저장할 수도 있습니다.)
해시맵의 데이터를 변경하고 싶을 때는 키에 이미 값이 할당되어 있을 경우에 대한 처리 방법을 결정해야 합니다.
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Blue"), 25);
println!("{:?}", scores);
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.entry(String::from("Yellow")).or_insert(50);
scores.entry(String::from("Blue")).or_insert(50);
println!("{:?}", scores);
use std::collections::HashMap;
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1;
}
println!("{:?}", map);
*
)를 사용하여 count를 역참조해야 합니다.