Sửa lỗi error[E0106]: missing lifetime specifier trong Rust

intermediate🦀 Rust2026-03-18| Rust 1.40+ (mọi edition), mọi hệ điều hành (Linux, macOS, Windows)

Error Message

error[E0106]: missing lifetime specifier
#rust#lifetime#reference#annotation

TL;DR

Trong code của bạn có một tham chiếu (&T) bên trong một trường của struct, chữ ký hàm, hoặc một block impl — và Rust không thể xác định nó tồn tại bao lâu. Cách sửa là dùng một tham số lifetime có tên như 'a. Nó cho trình biên dịch biết chính xác quan hệ giữa thời gian hợp lệ của tham chiếu với kiểu hoặc hàm xung quanh.

// Trước (lỗi)
struct Config {
    name: &str,  // error[E0106]: missing lifetime specifier
}

// Sau (đã sửa)
struct Config<'a> {
    name: &'a str,
}

Nguyên nhân gây ra lỗi này

Rust theo dõi thời gian tồn tại của mọi tham chiếu — đó là đảm bảo an toàn bộ nhớ của nó, được kiểm tra tại thời điểm biên dịch. Khi một tham chiếu xuất hiện trong trường của struct hoặc trong chữ ký hàm có nhiều tham chiếu, trình biên dịch cần hướng dẫn rõ ràng: một lifetime annotation cho biết tham chiếu nào tồn tại lâu hơn tham chiếu nào.

Ba vị trí thường gặp nhất:

  • Trường của struct chứa một tham chiếu (&str, &T)
  • Hàm trả về tham chiếu và nhận nhiều tham số tham chiếu
  • Block impl cho struct có tham số lifetime

Quy tắc elision lifetime của Rust xử lý nhiều trường hợp đơn giản một cách tự động. Tuy nhiên, chúng không bao phủ mọi pattern — và khi elision không thể giải quyết được, bạn sẽ gặp error[E0106].

Cách sửa 1 — Struct có trường tham chiếu

Đây là nguyên nhân phổ biến nhất. Thêm tham số lifetime vào struct, sau đó đánh dấu từng trường tham chiếu với nó.

// Lỗi
struct Article {
    title: &str,
    body: &str,
}

// Đã sửa
struct Article<'a> {
    title: &'a str,
    body: &'a str,
}

Bất kỳ code nào tạo hoặc sử dụng Article giờ đây đều mang lifetime — nhưng trong thực tế, trình biên dịch xử lý hầu hết các điểm gọi tự động thông qua elision:

fn print_article(article: &Article) {  // Rust tự suy luận ở đây — không sao
    println!("{}", article.title);
}

fn main() {
    let title = String::from("Rust Lifetimes");
    let body  = String::from("Chúng giúp bạn an toàn.");
    let article = Article {
        title: &title,
        body:  &body,
    };
    print_article(&article);
}

Cách sửa 2 — Hàm trả về tham chiếu

Trả về tham chiếu từ hàm yêu cầu Rust biết nó đến từ đầu vào nào. Một tham chiếu đầu vào? Elision xử lý được. Hai hoặc nhiều hơn? Bạn cần đánh dấu rõ ràng.

// Lỗi — Rust không biết giá trị trả về mượn từ `a` hay `b`
fn longest(a: &str, b: &str) -> &str {
    if a.len() > b.len() { a } else { b }
}

// Đã sửa — cả hai đầu vào chia sẻ lifetime 'a, đầu ra tồn tại tối đa cùng thời gian
fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
    if a.len() > b.len() { a } else { b }
}

Annotation 'a nói rằng: "tham chiếu trả về hợp lệ chừng nào cả hai ab còn hợp lệ." Trong thực tế, điều đó có nghĩa là lifetime ngắn hơn trong hai cái sẽ quyết định.

Cách sửa 3 — Block impl cho struct có lifetime

Các phương thức trên struct có tham số lifetime cần lifetime đó trên chính từ khóa impl. Quên điều này là lỗi dễ mắc phải.

struct Parser<'a> {
    input: &'a str,
    pos: usize,
}

// Lỗi
impl Parser {
    fn remaining(&self) -> &str {
        &self.input[self.pos..]
    }
}

// Đã sửa
impl<'a> Parser<'a> {
    fn remaining(&self) -> &str {
        &self.input[self.pos..]
    }
}

Cách sửa 4 — Cân nhắc sở hữu dữ liệu thay vì mượn

Đôi khi lifetime không phải là công cụ phù hợp. Nếu thêm 'a khắp nơi khiến code khó theo dõi hơn, hãy sở hữu dữ liệu hoàn toàn:

// Thay vì mượn một &str...
struct Config<'a> {
    name: &'a str,
}

// ...sở hữu một String
struct Config {
    name: String,
}

Bạn phải trả giá bằng một lần cấp phát heap nhỏ, nhưng struct đơn giản hơn và dễ truyền đi hơn nhiều. Sự đánh đổi đó thường có lợi hơn trừ khi bạn đang ở một đoạn code thực thi thường xuyên hoặc làm việc trực tiếp với các slice mượn từ API bên ngoài.

Kiểm tra kết quả

Build lại project:

cargo build

Không có error[E0106] trong output nghĩa là các lifetime đã được giải quyết. Trong lúc đó, hãy chạy Clippy để bắt các anti-pattern lifetime mà trình biên dịch có thể đã bỏ qua:

cargo clippy

Vẫn chưa chắc nên dùng annotation nào? Hỏi trực tiếp trình biên dịch:

rustc --explain E0106

Lệnh đó in ra giải thích đầy đủ kèm ví dụ — ngay trong terminal của bạn, không cần mở trình duyệt.

Hướng dẫn quyết định nhanh

  • Struct có trường &str hoặc &T → thêm <'a> vào struct và đánh dấu trường đó.
  • Hàm trả về tham chiếu với nhiều tham chiếu đầu vào → đánh dấu đầu ra mượn từ đầu vào nào.
  • Block impl trên struct có lifetime → ánh chiếu tham số lifetime trên impl<'a> MyStruct<'a>.
  • Tất cả các trường hợp khác → cân nhắc chuyển sang kiểu sở hữu (String thay vì &str, Vec<T> thay vì &[T]).

Related Error Notes