HRTB는 Higher-Rank Trait Bound의 약자다. 기존 라이프타임의 한계를 해결하기 위해 만들어진 문법이다. 예를 들면 다음과 같은 상황과 같다:
fn foo<'a, F>(closure: F)
where
F: Fn(&'a i32),
{
let bar = 42;
closure(&bar); // Compile errors here
}
보통 클로저에 참조를 넘겨야할 때 이런 이슈를 꽤 자주 마주친다. 지금 보면 인자 foo가 Fn(&'a i32) 함수 타입 트레잇을 받고 있다. 위 코드를 컴파일해보면 에러가 난다.
위 코드가 왜 에러가 나냐면, 러스트 컴파일러에서 참조 라이프타임을 추론할 때 caller의 라이프타임을 적용시킨다. main 함수에서 foo를 호출했다고 하자. 그럼 &'a 라이프타임은 자연스럽게 main 스코프와 같은 수명을 갖게된다. 즉, 지역 참조인 &bar의 수명이 성립이 안되는 거다. (main보다 빨리 드랍된다.)
그래서 해결책으로 HRTB를 사용한다.
fn foo<F>(closure: F)
where
F: for<'a> Fn(&'a i32),
{
let bar = 42;
closure(&bar);
}
위와 같이 작성할 수 있다. 차이점은 아까 코드와 다르게 제네릭 정의에 함수에 붙지 않고 F에 직접 for<'a> 문법으로 바인딩해준다..
이게 무슨 말이냐면 선언하는 주체를 F에게 넘기곘다는 것이다. 즉 기존엔 caller가 라이프타임의 수명을 정했지만 이젠 F가 정한다는 것이다. 사실상 뭐가 들어오든 상관 없는 셈.
이름이 Higher-Rank인 이유도 여기서 나온다. 일반적인 라이프타임 정의는 rank-1, 즉 함수 시그니처 바깥에 있고 위와 같은 바인딩은 trait bound 안쪽, 즉 rank-2가 된다.
참조