언어 항목
컴파일러에는 플러그인 방식으로 끼워 넣을 수 있는 연산이 몇 가지 있습니다. 즉, 언어에 하드코딩되어 있지 않고 라이브러리에 구현되어 있으며, 특별한 표식으로 컴파일러에 그 존재를 알리는 기능입니다. 이 표식은 #[lang = "..."] 속성이며, ...에는 여러 가지 값, 즉 여러 가지 ’언어 항목’이 들어갈 수 있습니다.
이러한 언어 항목 중 상당수는 add(trait core::ops::Add)나 future_trait(trait core::future::Future)처럼 합리적인 구현 방식이 하나뿐입니다. 다른 언어 항목은 특정한 목적을 달성하기 위해 재정의할 수 있습니다. 예를 들어 바이너리의 진입점을 제어할 수 있습니다.
언어 항목이 제공하는 기능은 다음과 같습니다:
- 트레이트를 통한 오버로드 가능한 연산자:
==,<, 역참조(*),+등의 연산자에 대응하는 트레이트는 모두 언어 항목으로 표시되어 있으며, 앞의 네 가지는 각각eq,ord,deref,add입니다. - 패닉과 스택 언와인딩:
eh_personality,panic,panic_bounds_checks언어 항목. - 컴파일러가 사용하는 타입의 속성을 나타내는 데 쓰이는
std::marker의 트레이트:send,sync,copy언어 항목입니다. core::marker에 있는, 변성(variance)을 나타내는 데 쓰이는 특수 마커 타입:phantom_data언어 항목입니다.
언어 항목은 컴파일러가 지연 로드합니다. 예를 들어 Box를 전혀 사용하지 않는다면 exchange_malloc과 box_free 함수를 정의할 필요가 없습니다. 어떤 항목이 필요한데 현재 크레이트나 그 크레이트가 의존하는 어떤 크레이트에서도 찾을 수 없으면 rustc가 오류를 냅니다.
대부분의 언어 항목은 core 라이브러리에 정의되어 있지만, #![no_std]로 실행 파일을 빌드하려는 경우에는 보통 std가 제공하는 몇 가지 언어 항목을 직접 정의해야 합니다.
언어 항목 가져오기
tcx.lang_items()를 호출하여 언어 항목을 가져올 수 있습니다.
다음은 trait Sized {} 언어 항목을 가져오는 간단한 예제입니다:
#![allow(unused)]
fn main() {
// Note that in case of `#![no_core]`, the trait is not available.
if let Some(sized_trait_def_id) = tcx.lang_items().sized_trait() {
// do something with `sized_trait_def_id`
}
}
sized_trait()는 DefId 자체가 아니라 Option을 반환한다는 점에 유의하십시오. 언어 항목은 표준 라이브러리에 정의되어 있으므로, 누군가 #로 컴파일하면 해당 언어 항목이 존재하지 않을 수 있기 때문입니다. 다음 중 하나를 선택할 수 있습니다:
- 계속 진행하는 데 해당 언어 항목이 반드시 필요하다면 하드 오류를 내십시오(사용자 코드에서도 발생할 수 있는 상황이므로 패닉하지 마십시오).
DefId로 하려던 작업을 생략하고 제한된 기능으로 계속 진행하십시오.
전체 언어 항목 목록
언어 항목은 다음 위치에서 찾을 수 있습니다:
- 컴파일러 문서의 전체 레퍼런스:
rustc_hir::LangItem - ripgrep으로 생성하는, 소스 위치가 포함된 자동 목록:
rg '#\[.*lang =' library/
언어 항목은 명시적으로 불안정한 기능이며 새 릴리스마다 바뀔 수 있다는 점에 유의하십시오.