일반적인 프로그래밍 언어에서는 에러 처리를 위한 예외 처리가 기본이다. 그렇지만 러스트(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");
}
}