logo MSJO.kr

Rust-004, 러스트 예외/에러 처리

2024-05-17
MsJ

일반적인 프로그래밍 언어에서는 에러 처리를 위한 예외 처리가 기본이다. 그렇지만 러스트(rust)는 예외 기능이 없다. 대신, 복구 가능한 에러를 위한 Result<T, E> 값과 복구 불가능한 에러가 발생했을 때 실행을 멈추는 panic! 매크로를 가지고 있다.1 또한 러스트는 다른 언어들이 가지는 Null이라는 기능이 없다. 러스트는 Null을 사용하지 않고, 존재하거나 존재하지 않음을 나타내는 개념을 나타내는 Option<T>을 이용한다.2

Result 및 Option 정의
enum Result<T, E> {
    Ok(T),
    Err(E)
}
enum Option<T> {
    None,
    Some(T)
}

여기에서 사용하는 대부분의 예제는 mithradates의 Easy Rust Korean를 참고하였다.

Option 예제
fn take_fifth(value: Vec<i32>) -> Option<i32> {
    if value.len() < 5 {
        None
    } else {
        Some(value[4])
    }
}

fn main() {
    let new_vec1 = vec![1, 2, 3, 4, 5];
    let index1 = take_fifth(new_vec1);

    match index1 {
        Some(number) => println!("I got a number: {}", number),
        None => println!("There was nothing inside"),
    }

    let new_vec2 = vec![1, 2];
    let index2 = take_fifth(new_vec2);

    if index2.is_some() {
        println!("I got a number: {}", index2.unwrap());
    } else {
        println!("There was nothing inside");
    }
}
Result 예제
fn check_error(input: i32) -> Result<(), ()> {
    if input % 2 == 0 {
        Ok(())
    } else {
        Err(())
    }
}

fn main() {
    if check_error(5).is_ok() {
        println!("It's okay, guys!");
    } else {
        println!("It's an error, guys!");
    }

    match check_error(4) {
        Ok(..) => println!("It's okay, guys!"),
        Err(..) => println!("It's an error, guys!")
    }
}
fn check_if_five(number: i32) -> Result<i32, String> {
    match number {
        5 => Ok(number),
        _ => Err("Sorry, the number wasn't five.".to_string()),
    }
}

fn main() {
    let mut result_vec = Vec::new(); // Vec<Result<i32, String>>

    for number in 2..=7 {
        result_vec.push(check_if_five(number));
    }

    println!("{:#?}", result_vec);
}
fn parse_number(number: &str) -> Result<i32, std::num::ParseIntError> {
    number.parse()
}

fn main() {
    let mut result_vec: Vec<Result<i32, std::num::ParseIntError>> = vec![];
    result_vec.push(parse_number("8"));
    result_vec.push(parse_number("one"));
    result_vec.push(parse_number("7"));

    for number in result_vec {
        if number.is_ok() {
            println!("Ok: {:?}", number.unwrap())
        } else {
            println!("Err: {:?}", number.unwrap_err().kind())
        }
    }
}
fn parse_number(number: &str) -> Result<i32, std::num::ParseIntError> {
    number.parse()
}

fn main() {
    let mut result_vec: Vec<Result<i32, std::num::ParseIntError>> = vec![];
    result_vec.push(parse_number("8"));
    result_vec.push(parse_number("one"));
    result_vec.push(parse_number("7"));

    for index in 0..result_vec.iter().count() {
        if let Some(number) = result_vec.get(index) {
            println!("{:?}", number.as_ref().unwrap_or(&0));
        }
    }
}
fn main() {
    let item_vec = vec![vec!["홍길동", "홍길서", "홍길남", "홍길북", "10"], vec!["가나닭", "20", "30"]];

    for mut item in item_vec {
        while let Some(info) = item.pop() {
            if let Ok(number) = info.parse::<i32>() {
                println!("The number is: {}", number);
            }
        }
    }
}
rust 예외처리
fn main() {
    let item_vec = vec![vec!["홍길동", "10"], vec!["가나닭", "20", "30"]];

    for mut item in item_vec {
        while let Some(info) = item.pop() {
            if let Ok(number) = info.parse::<i32>() {
                println!("The number is: {}", number);
            } else if let Err(e) = info.parse::<i32>() {
                println!("Error : {}", e);
            }
        }
    }
}
fn main() {
    let item_vec = vec![vec!["홍길동", "10"], vec!["가나닭", "20", "30"]];

    for mut item in item_vec {
        while let Some(info) = item.pop() {
            if let Ok(number) = info.parse::<i32>() {
                println!("The number is: {}", number);
            } else {
                println!("Error : {:?}", info.parse::<i32>().err().unwrap().kind());
            }
        }
    }
}
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!["one", "2", "3"] {
        let parsed = parse_str(item);
        println!("{:?}", parsed);
    }

    println!("-----------------");

    let my_vec = vec!["one", "2", "3"];
    let result = my_vec.iter().filter_map(|&s| parse_str(s).ok()).collect::<Vec<_>>();
    for item in result {
        println!("{:?}", item);
    }
}
use std::num::ParseIntError;

fn parse_str(input: &str) -> Result<i32, ParseIntError> {
    let parsed_number = input.parse::<i32>()?;
    Ok(parsed_number)
}

fn main() {
    let mut result_number: Vec<i32> = Vec::new();
    let mut result_string: Vec<String> = Vec::new();

    for item in vec!["one", "2", "3"] {
        let parsed = parse_str(item);
        if let Ok(number) = parsed {
            result_number.push(number);
        } else if let Err(e) = parsed {
            result_string.push(item.to_string() + "#:$" + &e.to_string());
        }
    }

    println!("{:?}", result_number);
    println!("{:?}", result_string);

    for n in result_number {
        println!("{}", n);
    }

    for s in result_string {
        println!("{}", s.split("#:$").next().unwrap());
        println!("{}", s.split("#:$").fold("".to_string(), |_, b| b.to_string()));
    }
}

예외처리 추가예제3

use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};

fn handle_client(mut stream: TcpStream) {
    let mut buffer = [0; 1024];

    if stream.read(&mut buffer).is_ok() {
        println!("success to read from client!");
    } else {
        println!("Failed to read from client!");
    }

    let request = String::from_utf8_lossy(&buffer[..]);
    println!("Received request: {}", request);

    let response = "Hello, Client!".as_bytes();
    let result = stream.write(response);

    match result {
        Ok(size) => println!("{}", size),
        Err(_) => println!("Failed to write response!"),
    }
}

fn main() {
    let listener = TcpListener::bind("127.0.0.1:8080");

    if let Ok(result) = listener {
        for stream in result.incoming() {
            match stream {
                Ok(stream) => {
                    std::thread::spawn(|| handle_client(stream));
                }
                Err(e) => {
                    eprintln!("Failed to establish connection: {}", e);
                }
            }
        }
    } else {
        println!("Failed to bind to address");
    }
}
Reference
  1. doc.rust-kr.org, “rust 에러처리”
  2. snowapril.github.io, “Rust가 Null을 도입하지 않은 이유”
  3. youtube.com/@BekBrace, “Network Programming in Rust - Building a TCP Server”

Prεv(Θld)   Nεxt(Nεw)
Content
Search     RSS Feed     BY-NC-ND