Как я могу получить доступ к месту вызова функции каждый раз, когда она вызывается?

Я хотел бы написать функцию, которая обращается к файлу и номеру строки места, в котором он вызывается.

Это выглядело бы так:

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`
}

игровая площадка

Другие вопросы по тегам