Как я могу получить доступ к месту вызова функции каждый раз, когда она вызывается?
Я хотел бы написать функцию, которая обращается к файлу и номеру строки места, в котором он вызывается.
Это выглядело бы так:
fn main() {
prints_calling_location(); // would print `called from line: 2`
prints_calling_location(); // would print `called from line: 3`
}
fn prints_calling_location() {
let caller_line_number = /* ??? */;
println!("called from line: {}", caller_line_number);
}
2 ответа
RFC 2091: неявное местоположение вызывающего добавляетtrack_caller
функция, которая позволяет функции получать доступ к местоположению вызывающего абонента.
Краткий ответ: чтобы получить место, в котором вызывается ваша функция, отметьте его #[track_caller]
и использовать std::panic::Location::caller
в его теле.
Следуя этому ответу, ваш пример будет выглядеть так:
#![feature(track_caller)]
fn main() {
prints_calling_location(); // would print `called from line: 2`
prints_calling_location(); // would print `called from line: 3`
}
#[track_caller]
fn prints_calling_location() {
let caller_location = std::panic::Location::caller();
let caller_line_number = caller_location.line();
println!("called from line: {}", caller_line_number);
}
В частности, функция std::panic::Location::caller
имеет два поведения:
- Внутри функции, отмеченной
#[track_caller]
, он возвращает&'static Location<'static>
который вы можете использовать, чтобы узнать номер файла, номер строки и номер столбца, в котором вызывается ваша функция. В функции, у которой нет
#[track_caller]
, он имеет склонное к ошибкам поведение, возвращая фактическое место, где вы его вызывали, а не то, где вызывается ваша функция, например:#![feature(track_caller)] fn main() { oops(); // ^ prints `line: 10` instead of the expected `line: 4` } // note: missing #[track_caller] here fn oops() { println!("line: {}", std::panic::Location::caller().line()); }
Альтернативой использованию "Неявного местоположения вызывающего абонента" (который может быть недоступен / не подходящим для вас по какой-либо причине) является использование метода C. Т.е. спрячьте свою функцию за макросом.
macro_rules! prints_calling_location {
() => {
let caller_line_number = line!();
println!("called from line: {}", caller_line_number);
};
}
fn main() {
prints_calling_location!(); // prints `called from line: 10`
prints_calling_location!(); // prints `called from line: 11`
}