HashMap : key - value
key와 value 는 어떤 타입도 될 수 있음
(key)String -> (value)Vec<String>
의 hashMap 을 만들고 싶다면 다음과 같이 사용
// HashMap<String, Vec<String>>
hashMap example
use std::collections::HashMap;
struct City{
name: String,
population: HashMap<u32, u32> // year -> population
}
fn main(){
let mut tallin = City {
name : "Tallin".to_string(),
population: HashMap::new()
};
tallin.population.insert(1372, 3_250);
tallin.population.insert(1851, 24_000);
tallin.population.insert(2020, 437_619);
for(year, population) in tallin.population{
println!("In the year {} the population was {}", year, population)
}
}
1372년, 1851년, 2020년의 순서로 나오지 않음. (순서는 완전 랜덤)
hashMap 은 순서를 정의할 수 없는 특징이 있음.
BTreeMap : ordering 이 가능한 HashMap
order가 필요없다면 HashMap, 필요하다면 BTreeMap(상대적으로 느림)
BTreeMap 예시
use std::collections::BTreeMap;
struct City{
name: String,
population: BTreeMap<u32, u32> // year -> population
}
fn main(){
let mut tallin = City {
name : "Tallin".to_string(),
population: BTreeMap::new()
};
tallin.population.insert(1372, 3_250);
tallin.population.insert(1851, 24_000);
tallin.population.insert(2020, 437_619);
for(year, population) in tallin.population{
println!("In the year {} the population was {}", year, population)
}
}
// 1372년 -> 1851년 -> 2020년 순서가 보장됨
HashMap 의 값을 불러오는 방법
(안전x 방법)
use std::collections::HashMap;
fn main(){
let canadian_cities = vec!["Calgary", "Vancouver", "Gimli"];
let german_cities = vec!["Karlsruhe", "Bad Doberan", "Bielefeld"];
let mut city_hashmap = HashMap::new();
for city in canadian_cities{
city_hashmap.insert(city, "Canada");
}
for city in german_cities{
city_hashmap.insert(city, "Germany");
}
println!("{:?}", city_hashmap["Bielefeld"]); // 정상 출력 (Bielefeld 라는 key가 존재함)
println!("{:?}", city_hashmap["Bielefeld123"]); // key 가 존재하지 않아서 오류 발생
}
(안전한 방법, .get 사용)
.get을 사용하면 "None"을 반환
use std::collections::HashMap;
fn main(){
let canadian_cities = vec!["Calgary", "Vancouver", "Gimli"];
let german_cities = vec!["Karlsruhe", "Bad Doberan", "Bielefeld"];
let mut city_hashmap = HashMap::new();
for city in canadian_cities{
city_hashmap.insert(city, "Canada");
}
for city in german_cities{
city_hashmap.insert(city, "Germany");
}
println!("{:?}", city_hashmap.get("Bielefeld")); // Some("Germany") 출력
println!("{:?}", city_hashmap.get("Bielefeld123")); // None 출력
}
이미 값이 존재하는 key 에 대해 insert하게 되면 덮어쓰기가 됨.
use std::collections::HashMap;
fn main(){
let mut book_hashmap = HashMap::new();
book_hashmap.insert(1, "Book1");
book_hashmap.insert(1, "Book2");
book_hashmap.insert(1, "Book3");
book_hashmap.insert(1, "Book4");
println!("{:?}", book_hashmap.get(&1)); // hashmap 에게 소유권을 넘기지 않고 reference 만 제공하기 위해 &1 사용
}
is_none 활용
use std::collections::HashMap;
fn main(){
let mut book_hashmap = HashMap::new();
book_hashmap.insert(1, "Book1");
if book_hashmap.get(&1).is_none() {
book_hashmap.insert(1, "Book1");
} else {
println!("Already got a book");
}
}
use std::collections::HashMap;
fn main(){
let mut book_hashmap = HashMap::new();
book_hashmap.insert(1, "Book1");
if let Some(book_name) = book_hashmap.get(&1) {
println!("Already got a book : {}", book_name);
} else {
book_hashmap.insert(1, "Book1");
}
}
Entry Method
use std::collections::HashMap;
fn main(){
let book_collection = vec![
"book1",
"book2",
"book3",
"book4",
"book4",
];
let mut book_hashmap = HashMap::new();
for book in book_collection{
book_hashmap.entry(book).or_insert(true);
}
for (book, true_or_false) in book_hashmap{
println!("Do we have {}? : {}", book, true_or_false);
}
}
.entry() method
pub fn entry(&mut self, key: K) -> Entry<K, V>
pub enum Entry<'a, K: 'a, V: 'a> {
Occupied(OccupiedEntry<'a, K, V>),
Vacant(VacantEntry<'a, K, V>),
}
Entry.or_insert() 는 &'a mut 을 반환하기 때문에 값을 바꿀 수 있음
use std::collections::HashMap;
fn main(){
let book_collection = vec![
"book1",
"book2",
"book3",
"book4",
"book4",
];
let mut book_hashmap = HashMap::new();
for book in book_collection{
let number_of_books = book_hashmap.entry(book).or_insert(0); // number_of_books -> &ref
*number_of_books += 1;
}
for (book, number) in book_hashmap{
println!("{}: {}copies", book, number);
}
}
use std::collections::HashMap;
fn main(){
let data = vec![
("male", 9),
("female", 5),
("male", 0),
("female", 6),
("female", 5),
("male", 10),
];
let mut survey_hash = HashMap::new();
for item in data { // (&str, i32)
survey_hash.entry(item.0).or_insert(Vec::new()).push(item.1);
}
for (male_or_female, numbers) in survey_hash{
println!("{:?}, {:?}", male_or_female, numbers)
}
}
HashSet
use std::collections::HashSet;
fn main(){
let many_numbers = vec![1,3,5,7,7,9];
let mut number_hashset = HashSet::new();
for number in many_numbers {
number_hashset.insert(number);
}
let hashset_length = number_hashset.len(); // hashset length
println!("There are {} unique numbers, so we are missing {}", hashset_length, 10-hashset_length);
let mut missing_vec = vec![];
for number in 0..10{
if number_hashset.get(&number).is_none() {
missing_vec.push(number);
}
}
print!("Missing numbers : ");
for number in missing_vec{
print!("{} ", number);
}
}
Set 에서도 Map과 동일하게 순서가 중요하다면 BTreeSet 사용!
binaryHeap : 아직 실제로 써본적은 없다고 함
use std::collections::BinaryHeap;
fn show_remainder(input: &BinaryHeap<i32>) -> Vec<i32> {
let mut remainder_vec = vec![];
for number in input {
remainder_vec.push(*number)
}
remainder_vec
}
fn main(){
let many_numbers = vec![0, 5, 10, 15, 20, 25, 30];
let mut my_heap = BinaryHeap::new();
for number in many_numbers{
my_heap.push(number);
}
while let Some(number) = my_heap.pop(){
println!("Popped off {}. Remaining numbers are : {:?}", number, show_remainder(&my_heap));
}
}
/* Output
Popped off 30. Remaining numbers are : [25, 15, 20, 0, 10, 5]
Popped off 25. Remaining numbers are : [20, 15, 5, 0, 10]
Popped off 20. Remaining numbers are : [15, 10, 5, 0]
Popped off 15. Remaining numbers are : [10, 0, 5]
Popped off 10. Remaining numbers are : [5, 0]
Popped off 5. Remaining numbers are : [0]
Popped off 0. Remaining numbers are : []
*/
-> 첫 번째 요소는 가장 큰 값, 나머지 요소들의 순서는 일관되지 않음
Most popular Usage : Priority Queue
예시 2
use std::collections::BinaryHeap;
fn main(){
let mut jobs = BinaryHeap::new();
jobs.push((100, "Write back to email from the CEO"));
jobs.push((80, "보고서 마감"));
jobs.push((5, "Youtube 시청"));
jobs.push((70, "동료들에게 감사인사 전하기"));
jobs.push((30, "다음 고용계획 작성"));
while let Some(job) = jobs.pop(){
println!("You need to: {}", job.1);
}
}
VecDeque
Vec의 경우
fn main(){
let my_vec = vec![8,9,10];
}
.pop : 맨 마지막값을 뺌
.push : 맨 마지막에 값을 넣음
Vec::with_capacity(10) : reallocation 없이 빠르게 사용
.remove(idx) : idx 의 값을 빼고 나머지 값들의 idx 를 한자리씩 앞으로 이동시킴
다음 상황에서 연산량이 많아서 오래걸리는 처리를 VecDeque 를 사용해서 빠르게 처리할 수 있음
// 오래 걸리는 코드
fn main(){
let mut my_vec = vec![0; 600_000]; // 0이 60만개있는 vec
for i in 0..600_000 {
my_vec.remove(0);
}
}
// VecDeque 사용
use std::collections::VecDeque;
fn main(){
let mut my_vec = VecDeque::from(vec![0; 600_000]);
for i in 0..600_000{
my_vec.pop_front();
}
}
Ring buffer 를 이용해서...........빠름
?
use std::num::ParseIntError
"8" 같은 값을 int로 변환, "8eo"같은 값은 에러 반환
use std::num::ParseIntError;
fn parse_str(input:&str) -> Result<i32, ParseIntError>{
let parsed_number = input.parse::<i32>()?; // 성공하면 넘어감 실패하면 return error
Ok(parsed_number)
}
fn main(){
for item in vec!["seven", "8", "9.0", "nice","6060"]{
let parsed = parse_str(item);
println!("{:?}", parsed);
}
}
/*
Err(ParseIntError { kind: InvalidDigit })
Ok(8)
Err(ParseIntError { kind: InvalidDigit })
Err(ParseIntError { kind: InvalidDigit })
Ok(6060)
*/
https://play.rust-lang.org/
에서 monaco editor 지원 시작
-> 인텔리센스(자동완성) 가능
format Strings
기존에는 다음과같이 써야만 했다면
println!("Books\n- {:?}\n- {:?}, book1, book2)
업데이트 이후에는 다음과같이 쓸 수 있게 됨
println!("Books\n- {book1:?}\n- {book2:?})
#[derive(Debug)]
struct Book{
title: String,
year: u16
}
fn main(){
let book1 = Book{
title : "Some title".to_string(),
year: 1919
};
let book2 = Book{
title : "Book2".to_string(),
year: 2020
};
println!("Books\n{book1:?}\n{book2:?}");
/* 아직 struct 안의 property 는 지원안함 */
// println!("My book name : {book1.title});
}
traits (다른 언어의 interface와 비슷)
struct Animal {
name : String
}
trait Canine {
fn bark(&self){
println!("Woof Woof!");
}
fn run(&self){
println!("I am running!");
}
}
impl Canine for Animal{
// 덮어쓰기 가능
fn bark(&self){
println!("멍멍!");
}
}
fn main(){
let my_animal = Animal{
name : "Mr. Mantle".to_string()
};
my_animal.bark();
my_animal.run();
}