#programminglanguage #rust >[!introduction] >러스트에서 함수는 상당한 지분을 차지합니다. 세부적인 구분을 제외한다면 러스트 프로그램은 대부분 함수로 이루어져 있다고 봐도 과언이 아닙니다. 이번 글에서는 러스트에서 함수를 만들고 사용하는 다양한 방법에 대하여 알아봅니다. ## 함수 선언 러스트에서는 `fn` 뒤에 함수 이름과 괄호를 붙여서 함수를 정의하고, 중괄호`{}`를 통해 함수 본문의 시작과 끝을 정한다. 그리고 함수를 호출할 때는 함수 이름 뒤에 괄호를 사용한다. 이때 호출하는 쪽에서 함수를 찾을 수 있다면 함수가 정의된 위치는 상관없다. ```rust fn main() { println!("Hello, world!"); another_function(); } fn another_function() { println!("Another function."); } ``` 매개변수*parameter*가 있다면 괄호 안에 반드시 각 매개변수의 이름과 타입을 선언해야 한다. 함수의 이름과 매개변수에 해당하는 부분을 시그니처*signature* 혹은 함수 원형*function prototype*이라고 부르는데, 매개변수가 있는 함수를 호출할 때는 시그니처에 맞게 인자*argument*를 괄호 안에 넣어 주어야 한다. ```rust fn main() { print_labeled_measurement(5, 'h'); } fn print_labeled_measurement(value: i32, unit_label: char) { println!("The measurement is: {value}{unit_label}"); } ``` ## `main` 함수 : 프로그램의 시작점 러스트로 만든 프로그램에서 다른 함수들과 조금 다른 지위를 가지는 함수가 있는데, 바로 `main` 함수다. 러스트의 프로그램은 주로 `main` 함수에서 시작해서 `main` 함수로 끝나는 구조를 가지고 있어서 `main` 함수는 프로그램의 실행 과정을 요약한 듯한 구조를 가질 때가 많다. ```rust fn main() { println!("Hello, world!"); } ``` ## 구문 ≠ 표현식 { #a14250} 앞서 살펴본 함수들은 모두 반환값이 없는 함수다. 하지만 그렇다고 해서 러스트에서 함수가 값을 반환하지 않는다는 것은 아니며, 러스트도 다른 언어처럼 함수가 값을 반환할 수 있다. 다만 다른 언어와 차이를 보이는 지점은 바로 값을 반환하는 방식이다. `five`라는 함수를 보면 값을 반환하는 함수가 어떻게 작성되는지 한 눈에 파악할 수 있다. ```rust fn five() -> i32 { 5 } fn main() { let x = five(); println!("The value of x is: {x}"); } ``` 만약 반환해야 하는 값이 있다면, 함수를 선언할 때 중괄호 이전에 `->`와 함께 반환할 값의 타입을 명시해야 한다. 그리고 반환할 값은 대부분의 코드와 달리 세미콜론`;`을 붙이지 말아야 하는데, 러스트가 다른 언어와 달리 구문*statement*과 표현식*expression*을 엄격하게 구분하기 때문이다. 러스트에서 세미콜론`;`이 붙는 모든 코드는 구문이고, 그렇지 않은 코드는 표현식이다. 러스트에서 함수의 본문은 구문과 표현식의 나열로 구성되는데, 구문은 어떤 동작을 수행하고 값을 반환하지 않는 반면 표현식은 식의 결과값을 평가한다. 그렇기 때문에 `x = y = 6`과 같은 코드는 러스트에서 작동하지 않는다. ```rust fn main() { let y = { let x = 3; x + 1 }; println!("The value of y is: {y}"); } ``` 여기서 `let x = 3;`은 구문이고 `x + 1`은 표현식이다. 구문을 통해 `x`라는 변수에 3이라는 값을 평가하는 표현식 `3`이 있기 때문에 `x`에 3이 들어가는 것이고, `x + 1`을 평가하면 4가 되고 표현식은 값을 반환하기 때문에 `y`라는 변수에 4라는 값이 대입되는 것이다. ## 메서드 러스트에서 함수를 사용하는 대표적인 상황 중 하나는 [[프로그래밍 언어/Rust/구조체#^eed5bb\|메서드]]*method*라 불리는 구조체의 기능을 구현하는 상황이다. 엄밀히 따지자면 메서드는 함수와 유사하되 다른 개념이지만, 함수와 여러 공통점을 가지고 있기 때문에 실제로 코드를 작성하고 보는 입장에서는 구조체에 딸린 함수라고 봐도 무방하다. ## 클로저 메서드는 일반 함수와 형태 상 많은 공통점을 가지고 있지만, 러스트는 [[클로저|클로저]]*closure*라는 전혀 다른 형태의 함수도 사용하고 있다. 클로저란 변수에 저장하거나 다른 함수에 인수로 전달할 수 있는 함수다. ## 함수 포인터 비록 C처럼 포인터를 직접 다룰 수는 없지만, 러스트에서도 함수 포인터*function pointer*를 통해 일반 함수를 함수에 전달할 수 있다. 러스트에서는 `fn`을 자료형으로 사용할 경우 `fn`타입을 함수 포인터라고 부르며, 이 타입의 매개변수에 인자로서 함수를 전달할 수 있다. 함수 포인터를 매개변수로 활용할 때는 아래와 같이 시그니처만 적어준다. ```rust fn add_one(x: i32) -> i32 { x + 1 } fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { f(arg) + f(arg) } fn main() { let answer = do_twice(add_one, 5); println!("The answer is: {}", answer); } ``` 이때 다른 타입처럼 `fn`을 반환 타입으로 사용할 수는 없다는 점을 조심해야 한다. --- ## 참고 자료 & 더보기 + [The Rust Programming Language(한국어판), 1.2. Hello World!](https://doc.rust-kr.org/ch01-02-hello-world.html) + [The Rust Programming Language(한국어판), 3.3. 함수](https://doc.rust-kr.org/ch03-03-how-functions-work.html) + [The Rust Programming Language(한국어판), 13.1 클로저: 자신의 환경을 캡처하는 익명 함수](https://doc.rust-kr.org/ch13-01-closures.html) + [The Rust Programming Language(한국어판), 19.4. 고급 함수와 클로저](https://doc.rust-kr.org/ch19-05-advanced-functions-and-closures.html)