Easy Rust Korean 051 ~ 060

Natreeum's Blog·2025년 11월 30일

Easy Rust Korean Study

목록 보기
5/5

051

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년 순서가 보장됨

052

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");
    }
}
  • if let 활용
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");
    }
}

053

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);
    }
}

054

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 사용!

055

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);
    }
}

056

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 를 이용해서...........빠름

057

?

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)
*/

058

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});
}

059, 60

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();
    
}
profile
BlockChain DEV

0개의 댓글