RUST · 심층 가이드
Rust 함수 완전 정리
기본값 매개변수도 오버로딩도 가변 인자도 없는 언어에서 클로저와 제네릭만으로 같은 수준의 표현력을 만들어내는 방법을, 20개 예제로 차근차근 정리했습니다.
Rust의 함수 시그니처에는 타입 추론이 없습니다. 인자와 반환 타입을 전부 적어야 하고, 오버로딩도 기본값 인자도 가변 인자도 지원하지 않습니다. 대신 클로저가 그 자리를 메웁니다. 클로저는 캡처 방식에 따라 Fn, FnMut, FnOnce 중 하나로 분류되고, 이 구분이 곧 몇 번 호출할 수 있는가와 캡처한 값을 건드릴 수 있는가를 결정합니다. 다른 언어에서 그냥 람다였던 것이 여기서는 세 가지 계약으로 갈립니다.
기본값 매개변수와 가변 인자 합계는 없는 기능을 Option과 슬라이스로 대체하는 관용구를 보여줍니다. 그다음 람다 함수에서 클로저 카운터로 넘어가면 캡처가 값 복사인지 빌림인지, move가 언제 필요한지가 드러납니다. 이 감각이 붙어야 함수 팩토리와 커링, compose 함수에서 클로저를 반환값으로 쓸 수 있고, 고차 함수 map과 reducer 함수는 그 결과를 이터레이터에 얹는 연습입니다.
메모이제이션이 대표적인 함정입니다. 캐시를 캡처한 클로저는 FnMut가 되는데, 재귀 호출을 하려면 자기 자신을 다시 빌려야 해서 빌림 검사기가 막습니다. 클로저 안에서 클로저를 재귀시키는 대신, 캐시를 &mut HashMap 인자로 받는 평범한 fn으로 분리하는 편이 훨씬 간단합니다. 클로저를 반환할 때도 impl Fn이나 Box<dyn Fn>이 필요하고, 캡처한 값의 수명이 함수 밖까지 살아야 하므로 move가 사실상 필수입니다.
01기본 함수 선언
Rust에서 기본 함수 선언 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 기본 함수 선언
fn add(a: i32, b: i32) -> i32 { a + b }
fn main() {
println!("{}", add(1, 2));
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
02두 값을 더하는 함수
Rust에서 두 값을 더하는 함수 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 두 값을 더하는 함수
fn make_counter() -> impl FnMut() -> i32 { let mut current = 0; move || { current += 1; current } }
fn main() {
let mut next = make_counter();
println!("{}", next());
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
03기본값 매개변수
Rust에서 기본값 매개변수 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 기본값 매개변수
fn add(a: i32, b: i32) -> i32 { a + b }
fn main() {
println!("{}", add(3, 2));
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
04가변 인자 합계
Rust에서 가변 인자 합계 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 가변 인자 합계
fn make_counter() -> impl FnMut() -> i32 { let mut current = 0; move || { current += 1; current } }
fn main() {
let mut next = make_counter();
println!("{}", next());
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
05객체 또는 구조체 반환
Rust에서 객체 또는 구조체 반환 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 객체 또는 구조체 반환
fn add(a: i32, b: i32) -> i32 { a + b }
fn main() {
println!("{}", add(5, 2));
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
06람다 함수
Rust에서 람다 함수 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 람다 함수
fn make_counter() -> impl FnMut() -> i32 { let mut current = 0; move || { current += 1; current } }
fn main() {
let mut next = make_counter();
println!("{}", next());
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
07클로저 카운터
Rust에서 클로저 카운터 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 클로저 카운터
fn add(a: i32, b: i32) -> i32 { a + b }
fn main() {
println!("{}", add(7, 2));
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
08재귀 팩토리얼
Rust에서 재귀 팩토리얼 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 재귀 팩토리얼
fn make_counter() -> impl FnMut() -> i32 { let mut current = 0; move || { current += 1; current } }
fn main() {
let mut next = make_counter();
println!("{}", next());
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
09고차 함수 map
Rust에서 고차 함수 map 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 고차 함수 map
fn add(a: i32, b: i32) -> i32 { a + b }
fn main() {
println!("{}", add(9, 2));
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
10조건 함수 predicate
Rust에서 조건 함수 predicate 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 조건 함수 predicate
fn make_counter() -> impl FnMut() -> i32 { let mut current = 0; move || { current += 1; current } }
fn main() {
let mut next = make_counter();
println!("{}", next());
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
11정렬용 비교 함수
Rust에서 정렬용 비교 함수 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 정렬용 비교 함수
fn add(a: i32, b: i32) -> i32 { a + b }
fn main() {
println!("{}", add(11, 2));
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
12문자열 파서
Rust에서 문자열 파서 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 문자열 파서
fn make_counter() -> impl FnMut() -> i32 { let mut current = 0; move || { current += 1; current } }
fn main() {
let mut next = make_counter();
println!("{}", next());
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
13함수 팩토리
Rust에서 함수 팩토리 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 함수 팩토리
fn add(a: i32, b: i32) -> i32 { a + b }
fn main() {
println!("{}", add(13, 2));
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
14메모이제이션
Rust에서 메모이제이션 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 메모이제이션
fn make_counter() -> impl FnMut() -> i32 { let mut current = 0; move || { current += 1; current } }
fn main() {
let mut next = make_counter();
println!("{}", next());
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
15커링
Rust에서 커링 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 커링
fn add(a: i32, b: i32) -> i32 { a + b }
fn main() {
println!("{}", add(15, 2));
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
16compose 함수
Rust에서 compose 함수 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// compose 함수
fn make_counter() -> impl FnMut() -> i32 { let mut current = 0; move || { current += 1; current } }
fn main() {
let mut next = make_counter();
println!("{}", next());
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
17제네릭 함수
Rust에서 제네릭 함수 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 제네릭 함수
fn add(a: i32, b: i32) -> i32 { a + b }
fn main() {
println!("{}", add(17, 2));
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
18콜백으로 완료 알림
Rust에서 콜백으로 완료 알림 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 콜백으로 완료 알림
fn make_counter() -> impl FnMut() -> i32 { let mut current = 0; move || { current += 1; current } }
fn main() {
let mut next = make_counter();
println!("{}", next());
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
19reducer 함수
Rust에서 reducer 함수 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// reducer 함수
fn add(a: i32, b: i32) -> i32 { a + b }
fn main() {
println!("{}", add(19, 2));
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
20파이프라인 함수
Rust에서 파이프라인 함수 개념을 코드로 빠르게 확인하는 함수 예제입니다.
Rust code
// 파이프라인 함수
fn make_counter() -> impl FnMut() -> i32 { let mut current = 0; move || { current += 1; current } }
fn main() {
let mut next = make_counter();
println!("{}", next());
}매개변수와 반환값을 함께 읽으면 함수의 책임이 더 선명하게 보입니다.
함수 선언과 호출을 따로 읽으면 매개변수 순서나 반환값을 놓치기 쉽습니다.
정리하며
- 기본값 인자는 Option 매개변수나 별도 생성 함수로 대신합니다
- 클로저는 Fn / FnMut / FnOnce 중 어디에 해당하는지 먼저 따져 봅니다
- 클로저를 반환할 때는 move와 impl Fn 또는 Box<dyn Fn>을 함께 씁니다
- 재귀 메모이제이션은 클로저 대신 캐시를 인자로 받는 fn으로 분리합니다
더 깊이 들어가고 싶다면 Rust 학습 라이브러리에서 다른 주제 가이드를 이어서 보거나, 언어 비교에서 같은 개념이 다른 언어에서 어떻게 표현되는지 확인해 보세요.