러스트에서 상수 표현식(const)은 컴파일 단계에서 계산되며, 프로그램이 실행되기 전에 값의 일부로 만드는 데 사용됩니다. 이러한 표현식은 배열의 크기, 정적 구조체의 값, 제네릭 매개변수 및 변경할 수 없는 상수가 필요할 때의 다른 상황에 지정하는 데 사용됩니다.
러스트에서는 다른 const 표현식 내에서 사용되거나 상수 변수를 초기화하는 데 사용할 수 있는 "상수" 함수(const fn)를 만들 수 있습니다. 컴파일러는 그러한 표현식에 허용되지 않은 작업(예: 메모리에 접근)이 포함되지 않도록 보장합니다.
예제:
const fn fib(n: u32) -> u32 { match n { 0 | 1 => 1, _ => fib(n - 1) + fib(n - 2), } } const F8: u32 = fib(8); const ARR: [u32; F8 as usize] = [0; F8 as usize]; // 크기가 34인 배열
이 예제에서 F8의 값과 배열 ARR의 크기는 컴파일 단계에서 계산됩니다.
const 함수와 일반 함수의 차이점은 무엇이며, 모든 함수를 const fn으로 선언할 수 있습니까?
답변:
아니요, 모든 함수를 const fn으로 선언할 수는 없습니다. const fn은 부작용이 없거나 안전하지 않은 메모리 작업을 포함할 수 없는 허용된 작업만 포함할 수 있습니다. 예를 들어 const fn에서 파일을 열거나 메모리를 동적으로 할당할 수 없습니다.
const fn add(x: i32, y: i32) -> i32 { x + y // 허용됨 } // 하지만 이 코드는 컴파일되지 않습니다: const fn fail() -> String { // 오류! String::from("err") }
이야기
한 프로젝트에서 상수 함수로 문자열의 해시 값을 컴파일 단계에서 계산하려고 했으나, 이 함수 내에서
HashMap의 기본 메서드와 메모리 할당을 사용했습니다. 프로그램은 컴파일되지 않았고 const fn에서의 작업 허용 불가에 대한 불명확한 오류를 발생시켰습니다.
이야기
큰 내장 시스템 개발에서, 한 개발자가 컴파일 단계에서 계산이 필요한 필드를 가진 상수 구조체를 정의했지만,
const fn으로 표시되지 않은 외부 crate의 함수를 초기화 내에서 사용했습니다. 이로 인해 정적 버퍼의 크기를 정의하는 데 이 논리를 사용할 수 없게 되었습니다.
이야기
코드에서
static과const의 차이를 혼동하여 런타임 중 "상수"를 변경하려고 시도했고, 러스트에서 상수는 값으로서 메모리에 배치되지 않고 컴파일러에 의해 사용되는 장소에 대체되므로 암묵적인 UB(정의되지 않은 동작)를 받았습니다.