두 함수 db_connect_와 db_connect는 동일한 목적(데이터베이스 연결 풀 생성)을 가지고 있지만, 에러 처리 방식에서 큰 차이가 있습니다. 이 차이를 분석하고, Rust에서 Result와 async/await를 사용하는 방법에 대해 설명하겠습니다.
db_connect_pub async fn db_connect_() -> PgPool {
dotenv().ok();
let url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let pool = PgPoolOptions::new().connect(&url).await.expect("Failed to connect to the database");
info!("Connected to the database");
pool
}
expect를 사용하여 에러 발생 시 프로그램을 즉시 종료합니다.std::env::var("DATABASE_URL").expect("DATABASE_URL must be set"): 환경 변수가 없으면 프로그램이 패닉(panic) 상태로 종료됩니다.PgPoolOptions::new().connect(&url).await.expect("Failed to connect to the database"): 데이터베이스 연결 실패 시 프로그램이 패닉 상태로 종료됩니다.PgPool을 직접 반환합니다.db_connectpub async fn db_connect() -> Result<PgPool, sqlx::Error> {
dotenv().ok();
let url = std::env::var("DATABASE_URL").map_err(|e| {
tracing::error!("Failed to read DATABASE_URL: {}", e);
sqlx::Error::Configuration(e.into())
})?;
let pool = PgPoolOptions::new()
.connect(&url)
.await
.map_err(|e| {
tracing::error!("Failed to connect to the database: {}", e);
e
})?;
info!("Connected to the database");
Ok(pool)
}
Result를 사용하여 에러를 호출자에게 전달합니다.std::env::var("DATABASE_URL").map_err(...): 환경 변수가 없으면 에러를 변환하고 로깅합니다.PgPoolOptions::new().connect(&url).await.map_err(...): 데이터베이스 연결 실패 시 에러를 변환하고 로깅합니다.Result<PgPool, sqlx::Error>를 반환합니다.Result 처리 방법Result란?Result는 Rust에서 에러 처리를 위한 열거형(enum)입니다.Result<T, E>는 성공 시 Ok(T)를, 실패 시 Err(E)를 반환합니다.unwrap:
Result가 Ok인 경우 값을 반환하고, Err인 경우 패닉을 발생시킵니다.let url = std::env::var("DATABASE_URL").unwrap();expect:
unwrap과 동일하지만, 패닉 메시지를 지정할 수 있습니다.let url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");? 연산자:
Result가 Ok인 경우 값을 반환하고, Err인 경우 현재 함수에서 빠져나가 에러를 전파합니다.let url = std::env::var("DATABASE_URL")?;map_err:
Result가 Err인 경우 에러를 변환합니다.let url = std::env::var("DATABASE_URL").map_err(|e| sqlx::Error::Configuration(e.into()))?;async/await와 Resultasync/await란?async는 비동기 함수를 정의할 때 사용합니다.await는 비동기 함수의 결과를 기다릴 때 사용합니다.Result와 함께 사용Result를 반환할 수 있습니다.await와 ?를 함께 사용하여 비동기 작업의 에러를 처리할 수 있습니다.예:
pub async fn db_connect() -> Result<PgPool, sqlx::Error> {
let url = std::env::var("DATABASE_URL")?; // 동기 작업
let pool = PgPoolOptions::new().connect(&url).await?; // 비동기 작업
Ok(pool)
}
unwrap 또는 expectlet url = std::env::var("DATABASE_URL").unwrap();
? 연산자let url = std::env::var("DATABASE_URL")?;
map_errlet url = std::env::var("DATABASE_URL").map_err(|e| {
tracing::error!("Failed to read DATABASE_URL: {}", e);
sqlx::Error::Configuration(e.into())
})?;
db_connect_:
expect를 사용하여 에러 발생 시 프로그램이 종료됩니다.db_connect:
Result를 사용하여 에러를 호출자에게 전파합니다.map_err를 사용하여 에러를 변환하고 로깅합니다.Rust에서의 에러 처리:
Result를 사용하여 에러를 명시적으로 처리합니다.? 연산자를 사용하여 에러를 전파합니다.map_err를 사용하여 에러를 변환하거나 로깅합니다.async/await:
await와 ?를 함께 사용하여 비동기 작업의 에러를 처리합니다.이를 통해 Rust에서 안정적이고 유지보수 가능한 코드를 작성할 수 있습니다! 🚀