Mastering Rust의 Result Enum을 위한 오류 처리
Ethan Miller
Product Engineer · Leapcell

Rust의 Result
타입
Rust는 독특한 오류 처리 메커니즘을 제공하는 시스템 프로그래밍 언어입니다. Rust에서 오류는 복구 가능한 오류와 복구 불가능한 오류의 두 가지 유형으로 분류됩니다. 복구 가능한 오류의 경우 Rust는 이를 처리하기 위해 Result
타입을 제공합니다.
Result
타입의 정의
Result
타입은 Ok
와 Err
두 가지 variant를 가진 열거형입니다. Ok
variant는 성공적인 작업을 나타내며 성공 값을 포함하고, Err
variant는 실패한 작업을 나타내며 오류 값을 포함합니다.
아래는 Result
타입의 정의입니다.
enum Result<T, E> { Ok(T), Err(E), }
여기서 T
는 성공 값의 타입을 나타내고, E
는 오류 값의 타입을 나타냅니다.
Result
타입의 용도
Result
타입은 함수 반환 값으로 흔히 사용됩니다. 함수가 성공적으로 실행되면 Ok
variant를 반환하고, 실패하면 Err
variant를 반환합니다.
아래는 간단한 예제입니다.
fn divide(numerator: f64, denominator: f64) -> Result<f64, String> { if denominator == 0.0 { Err("0으로 나눌 수 없습니다".to_string()) } else { Ok(numerator / denominator) } } fn main() { let result = divide(4.0, 2.0); match result { Ok(value) => println!("결과: {}", value), Err(e) => println!("오류: {}", e), } }
이 예제에서 divide
함수는 분자와 분모 두 개의 인수를 받습니다. 분모가 0
이면 Err
variant를 반환하고, 그렇지 않으면 Ok
variant를 반환합니다.
main
함수에서는 divide
함수를 호출하고 match
구문을 사용하여 반환 값을 처리합니다. 반환 값이 Ok
이면 결과를 출력하고, Err
이면 오류 메시지를 출력합니다.
Result
로 오류를 처리하는 방법
Result
타입을 반환하는 함수를 호출할 때 잠재적인 오류를 처리해야 합니다. 이를 수행하는 방법에는 여러 가지가 있습니다.
match
구문 사용
match
구문은 Rust에서 Result
타입 오류를 처리하는 가장 일반적인 방법입니다. 반환 값에 따라 다른 작업을 실행할 수 있습니다.
다음은 간단한 예입니다.
fn divide(numerator: f64, denominator: f64) -> Result<f64, String> { if denominator == 0.0 { Err("0으로 나눌 수 없습니다".to_string()) } else { Ok(numerator / denominator) } } fn main() { let result = divide(4.0, 2.0); match result { Ok(value) => println!("결과: {}", value), Err(e) => println!("오류: {}", e), } }
이 예제에서는 match
구문을 사용하여 divide
함수의 반환 값을 처리합니다. Ok
를 반환하면 결과를 출력하고, Err
를 반환하면 오류 메시지를 출력합니다.
if let
구문 사용
if let
구문은 match
의 단순화된 버전입니다. 하나의 case만 일치시킬 수 있으며 다른 case를 처리할 필요가 없습니다. if let
구문은 Result
타입의 한 가지 case만 신경 쓸 때 자주 사용됩니다.
다음은 간단한 예입니다.
fn divide(numerator: f64, denominator: f64) -> Result<f64, String> { if denominator == 0.0 { Err("0으로 나눌 수 없습니다".to_string()) } else { Ok(numerator / denominator) } } fn main() { let result = divide(4.0, 2.0); if let Ok(value) = result { println!("결과: {}", value); } }
이 예제에서는 if let
구문을 사용하여 divide
함수의 반환 값을 처리합니다. Ok
를 반환하면 결과를 출력하고, 그렇지 않으면 아무 일도 일어나지 않습니다.
?
연산자 사용
?
연산자는 함수 내에서 오류를 편리하게 전파할 수 있는 Rust의 특별한 구문입니다. Result
타입을 반환하는 함수를 호출할 때 ?
연산자는 오류 처리를 단순화할 수 있습니다.
다음은 간단한 예입니다.
fn divide(numerator: f64, denominator: f64) -> Result<f64, String> { if denominator == 0.0 { Err("0으로 나눌 수 없습니다".to_string()) } else { Ok(numerator / denominator) } } fn calculate(numerator: f64, denominator: f64) -> Result<f64, String> { let result = divide(numerator, denominator)?; Ok(result * 2.0) } fn main() { let result = calculate(4.0, 2.0); match result { Ok(value) => println!("결과: {}", value), Err(e) => println!("오류: {}", e), } }
이 예제에서 calculate
함수는 내부적으로 divide
함수를 호출하고 ?
연산자를 사용하여 오류 처리를 단순화합니다. divide
가 Err
를 반환하면 calculate
는 즉시 Err
를 반환하고, 그렇지 않으면 실행이 계속됩니다.
Result
의 일반적인 메서드
Result
타입은 오류 처리를 더 편리하게 만드는 여러 유용한 메서드를 제공합니다.
is_ok
및 is_err
메서드
is_ok
및 is_err
메서드는 Result
가 각각 Ok
또는 Err
variant인지 확인합니다.
다음은 간단한 예입니다.
fn divide(numerator: f64, denominator: f64) -> Result<f64, String> { if denominator == 0.0 { Err("0으로 나눌 수 없습니다".to_string()) } else { Ok(numerator / denominator) } } fn main() { let result = divide(4.0, 2.0); if result.is_ok() { println!("결과: {}", result.unwrap()); } else { println!("오류: {}", result.unwrap_err()); } }
이 예제에서는 is_ok
메서드를 사용하여 divide
의 반환 값이 Ok
인지 확인합니다. 그렇다면 unwrap
을 사용하여 성공 값을 가져와서 출력하고, 그렇지 않으면 unwrap_err
을 사용하여 오류 메시지를 가져와서 출력합니다.
unwrap
및 unwrap_err
메서드
unwrap
및 unwrap_err
메서드는 Result
에서 각각 성공 또는 오류 값을 검색합니다. Result
가 예상한 variant가 아니면 패닉이 발생합니다.
다음은 간단한 예입니다.
fn divide(numerator: f64, denominator: f64) -> Result<f64, String> { if denominator == 0.0 { Err("0으로 나눌 수 없습니다".to_string()) } else { Ok(numerator / denominator) } } fn main() { let result = divide(4.0, 2.0); let value = result.unwrap(); println!("결과: {}", value); }
이 예제에서는 unwrap
을 사용하여 divide
함수의 성공 값을 가져옵니다. 반환 값이 Ok
가 아니면 패닉이 발생합니다.
expect
및 expect_err
메서드
expect
및 expect_err
메서드는 unwrap
및 unwrap_err
과 유사하지만 사용자 정의 오류 메시지를 지정할 수 있습니다. Result
가 예상한 variant가 아니면 패닉이 발생하고 지정된 메시지가 출력됩니다.
다음은 간단한 예입니다.
fn divide(numerator: f64, denominator: f64) -> Result<f64, String> { if denominator == 0.0 { Err("0으로 나눌 수 없습니다".to_string()) } else { Ok(numerator / denominator) } } fn main() { let result = divide(4.0, 2.0); let value = result.expect("나누기 실패"); println!("결과: {}", value); }
이 예제에서는 expect
를 사용하여 divide
함수의 성공 값을 검색합니다. 반환 값이 Ok
가 아니면 패닉이 발생하고 지정된 오류 메시지가 출력됩니다.
Result
의 특징 및 장점
Result
타입은 다음과 같은 특징과 장점을 가지고 있습니다.
- 명시적인 오류 처리:
Result
타입은 프로그래머가 오류를 명시적으로 처리하도록 강제하여 오류가 무시되거나 간과되는 것을 방지합니다. - 타입 안전성:
Result
타입은 성공 또는 오류 값의 모든 타입을 담을 수 있는 제네릭 타입으로, 타입 안전성을 보장하고 타입 변환 오류를 방지합니다. - 편리한 오류 전파: Rust는 함수에서 오류를 쉽게 전파할 수 있도록
?
연산자를 제공합니다. - 쉬운 구성:
Result
타입은and
,or
,and_then
및or_else
와 같은 다양한 구성 메서드를 제공하여 여러Result
값을 더 쉽게 결합할 수 있습니다.
실제 코드에서 Result
사용
실제 코드에서는 사용자 정의 오류 타입을 정의하고 Result
타입을 사용하여 오류 정보를 반환하는 경우가 많습니다.
다음은 간단한 예입니다.
use std::num::ParseIntError; type Result<T> = std::result::Result<T, MyError>; #[derive(Debug)] enum MyError { DivideByZero, ParseIntError(ParseIntError), } impl From<ParseIntError> for MyError { fn from(e: ParseIntError) -> Self { MyError::ParseIntError(e) } } fn divide(numerator: &str, denominator: &str) -> Result<f64> { let numerator: f64 = numerator.parse()?; let denominator: f64 = denominator.parse()?; if denominator == 0.0 { Err(MyError::DivideByZero) } else { Ok(numerator / denominator) } } fn main() { let result = divide("4", "2"); match result { Ok(value) => println!("결과: {}", value), Err(e) => println!("오류: {:?}", e), } }
이 예제에서:
DivideByZero
및ParseIntError
의 두 가지 variant를 포함하는 사용자 정의 오류 타입MyError
를 정의합니다.MyError
를 오류 타입으로 설정하여 타입 별칭Result
를 정의합니다.divide
함수는 두 개의 문자열 인수를 취하고 이를f64
로 파싱하려고 시도합니다. 파싱에 실패하면?
연산자가 오류를 전파합니다. 분모가0
이면Err
variant가 반환되고, 그렇지 않으면 함수는Ok
를 반환합니다.
main
함수에서는 divide
를 호출하고 match
구문을 사용하여 반환 값을 처리합니다. Ok
를 반환하면 결과를 출력하고, Err
를 반환하면 오류 메시지를 출력합니다.
Result
로 파일 읽기/쓰기 오류 처리
파일 작업 시 파일이 없거나 권한이 부족한 경우와 같은 다양한 오류가 발생할 수 있습니다. 이러한 오류는 Result
타입을 사용하여 처리할 수 있습니다.
다음은 간단한 예입니다.
use std::fs; use std::io; fn read_file(path: &str) -> Result<String, io::Error> { fs::read_to_string(path) } fn main() { let result = read_file("test.txt"); match result { Ok(content) => println!("파일 내용: {}", content), Err(e) => println!("오류: {}", e), } }
이 예제에서:
read_file
함수는 파일 경로를 인수로 취하고fs::read_to_string
을 사용하여 파일 내용을 읽습니다.fs::read_to_string
은 파일 내용을 포함하는 성공 값과io::Error
타입의 오류 값을 가진Result
타입을 반환합니다.main
에서read_file
을 호출하고match
를 사용하여 반환 값을 처리합니다.Ok
를 반환하면 파일 내용이 출력되고,Err
를 반환하면 오류 메시지가 출력됩니다.
Result
로 네트워크 요청 오류 처리
네트워크 요청을 수행할 때 연결 시간 초과 또는 서버 오류와 같은 다양한 오류가 발생할 수 있습니다. 이러한 오류도 Result
타입을 사용하여 처리할 수 있습니다.
다음은 간단한 예입니다.
use std::io; use std::net::TcpStream; fn connect(host: &str) -> Result<TcpStream, io::Error> { TcpStream::connect(host) } fn main() { let result = connect("example.com:80"); match result { Ok(stream) => println!("{}(으)로 연결됨", stream.peer_addr().unwrap()), Err(e) => println!("오류: {}", e), } }
이 예제에서:
connect
함수는 호스트 주소를 인수로 취하고TcpStream::connect
를 사용하여 TCP 연결을 설정합니다.TcpStream::connect
는TcpStream
타입의 성공 값과io::Error
타입의 오류 값을 가진Result
타입을 반환합니다.main
에서connect
를 호출하고match
를 사용하여 반환 값을 처리합니다.Ok
를 반환하면 연결 정보가 출력되고,Err
를 반환하면 오류 메시지가 출력됩니다.
Result
및 오류 처리에 대한 모범 사례
Result
로 오류를 처리할 때 다음 모범 사례는 더 나은 코드를 작성하는 데 도움이 될 수 있습니다.
- 사용자 정의 오류 타입 정의: 사용자 정의 오류 타입은 오류 정보를 보다 효과적으로 구성하고 관리하는 데 도움이 됩니다.
?
연산자를 사용하여 오류 전파:?
연산자를 사용하면 함수에서 오류를 쉽게 전파할 수 있습니다.unwrap
및expect
의 과도한 사용 방지: 이러한 메서드는Err
variant가 발생하면 패닉을 유발합니다. 대신match
또는if let
을 사용하여 오류를 적절하게 처리하십시오.- 구성 메서드를 사용하여 여러
Result
값 결합:and
,or
,and_then
및or_else
와 같은 메서드는 여러Result
값을 효율적으로 결합하는 데 도움이 됩니다.
Rust 프로젝트 호스팅을 위한 최고의 선택, Leapcell입니다.
Leapcell은 웹 호스팅, 비동기 작업 및 Redis를 위한 차세대 서버리스 플랫폼입니다.
다국어 지원
- Node.js, Python, Go 또는 Rust로 개발하십시오.
무제한 프로젝트를 무료로 배포
- 사용량에 대해서만 비용을 지불하십시오. 요청도 없고 요금도 없습니다.
타의 추종을 불허하는 비용 효율성
- 유휴 요금 없이 사용한 만큼만 지불하십시오.
- 예: $25는 평균 응답 시간 60ms에서 694만 건의 요청을 지원합니다.
간소화된 개발자 경험
- 손쉬운 설정을 위한 직관적인 UI.
- 완전 자동화된 CI/CD 파이프라인 및 GitOps 통합.
- 실행 가능한 통찰력을 위한 실시간 메트릭 및 로깅.
손쉬운 확장성과 고성능
- 고도의 동시성을 쉽게 처리할 수 있도록 자동 확장됩니다.
- 운영 오버헤드가 전혀 없으므로 구축에만 집중하십시오.
문서에서 자세히 알아보십시오!
X에서 팔로우하세요: @LeapcellHQ