hyunsu blog

홈강좌Rust 입문·중급 47편 중 11편째

Rust 반환값 — 세미콜론 없는 마지막 줄이 돌려주는 값이다

목차 · 5
  1. 01세미콜론 하나로 E0308 이 난다
  2. 02세미콜론이 있으면 문, 없으면 식
  3. 03중괄호 블록도 값을 낸다
  4. 04실습 — 값 둘을 돌려주는 함수
  5. 05자주 묻는 질문

Rust 함수는 -> 타입 으로 돌려줄 값의 타입을 적고, 세미콜론 없는 마지막 줄의 값을 돌려준다. 그 줄에 습관대로 세미콜론을 붙이면 아무 값도 돌려주지 않게 되어 E0308 이 난다. 값을 둘 이상 돌려줄 때는 튜플을 쓴다.

01 세미콜론 하나로 E0308 이 난다

6편의 섭씨→화씨 계산을 함수로 빼 보자. 괄호 뒤의 -> f64 가 "f64 를 돌려준다" 는 뜻이다. 습관대로 계산 줄 끝에 세미콜론을 찍으면 이렇게 된다.

rust
fn to_fahrenheit(c: f64) -> f64 {
    c * 9.0 / 5.0 + 32.0;
}

fn main() {
    let f = to_fahrenheit(36.5);
    println!("{f}");
}
text
   Compiling convert v0.1.0 (~/projects/convert)
error[E0308]: mismatched types
 --> src/main.rs:1:29
  |
1 | fn to_fahrenheit(c: f64) -> f64 {
  |    -------------            ^^^ expected `f64`, found `()`
  |    |
  |    implicitly returns `()` as its body has no tail or `return` expression
2 |     c * 9.0 / 5.0 + 32.0;
  |                         - help: remove this semicolon to return this value

For more information about this error, try `rustc --explain E0308`.
error: could not compile `convert` (bin "convert") due to 1 previous error
  1. 무엇 — 타입이 안 맞는다(mismatched types). f64 를 돌려준다고 해 놓고(^^^), 실제로는 () 를 돌려준다. () 는 "값 없음" 이다.
  2. 어디 — 함수 이름 아래 줄이 이유를 말한다. 본문에 돌려줄 값이 없어서 "값 없음" 을 돌려주게 됐다(implicitly returns ()).
  3. 고치는 법 — 2번째 줄 끝을 - 로 짚고 help: remove this semicolon 이라고 한다. 세미콜론을 지운다.

02 세미콜론이 있으면 문, 없으면 식

Rust 는 코드 한 줄을 두 가지로 나눈다.

문 (statement)식 (expression)
끝세미콜론으로 끝난다세미콜론이 없다
값없다있다
예let x = 5;5 + 1 · c * 9.0 / 5.0 + 32.0

함수 본문의 마지막 줄이 식이면 그 값이 반환값이 된다. 다른 언어처럼 return 을 쓰지 않아도 된다. 세미콜론을 붙이는 순간 문이 되어 값이 사라진다. 그래서 위 함수가 "값 없음" 을 돌려준 것이다.

세미콜론을 지우면 컴파일되고 값이 나온다.

rust
fn to_fahrenheit(c: f64) -> f64 {
    c * 9.0 / 5.0 + 32.0
}

fn main() {
    let f = to_fahrenheit(30.0);
    println!("{f}");
}
text
   Compiling convert v0.1.0 (~/projects/convert)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.17s
     Running `target/debug/convert`
86

86.0 이 86 으로 찍힌 것은 6편에서 본 대로 .0 을 줄여 찍기 때문이다.

03 중괄호 블록도 값을 낸다

같은 규칙이 함수 밖에서도 통한다. 중괄호 블록(4편)의 마지막 줄이 식이면, 블록 전체가 그 값이 된다.

rust
fn main() {
    let total = {
        let price = 12000;
        let shipping = 3000;
        price + shipping
    };
    println!("{total}");
}
text
   Compiling block v0.1.0 (~/projects/block)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.18s
     Running `target/debug/block`
15000

블록 안에서 price 와 shipping 을 만들고, 세미콜론 없는 마지막 줄 price + shipping 이 블록의 값이 되어 total 에 담겼다. 블록 안의 두 변수는 블록이 끝나면 사라진다. 함수 본문도 사실 이런 블록이다.

04 실습 — 값 둘을 돌려주는 함수

피자 조각을 사람 수로 나눠 한 사람 몫과 남는 조각을 함께 돌려주자. 값이 둘이니 8편의 튜플로 묶는다.

rust
fn split(slices: i32, people: i32) -> (i32, i32) {
    (slices / people, slices % people)
}

fn main() {
    let (each, left) = split(7, 2);
    println!("each: {each}, left: {left}");
}
text
   Compiling pizza v0.1.0 (~/projects/pizza)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s
     Running `target/debug/pizza`
each: 3, left: 1

반환 타입 -> (i32, i32) 가 "정수 둘을 묶은 튜플을 돌려준다" 는 뜻이다. 마지막 줄 (slices / people, slices % people) 에 세미콜론이 없으니 이 튜플이 반환값이다. 받는 쪽에서는 let (each, left) = … 로 바로 풀어 담았다.

split(10, 3) 으로 바꿔 돌려 보자. 3 과 1 이 나와야 한다. 다음 편은 조건에 따라 다른 코드를 실행하는 if 다.

05 자주 묻는 질문

return 은 안 쓰나?

쓴다. 함수 중간에서 값을 돌려주고 일찍 끝낼 때 return 값; 을 쓴다. 함수 끝에서 돌려줄 때는 세미콜론 없는 마지막 식을 쓰는 것이 Rust 의 관례다.