Làm thế nào để chuyển đổi một chuỗi thành một & 'static str


92

Làm cách nào để chuyển đổi a Stringthành a &str? Cụ thể hơn, tôi muốn chuyển nó thành một strvới staticthời gian tồn tại ( &'static str).


Điều đó dường như không thể và cũng không mong muốn. 'staticthời gian tồn tại có nghĩa là chuỗi không bao giờ được phân bổ, tức là bị rò rỉ bộ nhớ. Tại sao bạn cần &'static strthay vì &'a strcho một số thích hợp 'a?

3
Nó sẽ trông như thế nào để chuyển đổi nó thành &'a str sau đó?
Christoph

Qua as_slice. Sẽ dễ dàng hơn để trợ giúp nếu bạn mô tả vấn đề cụ thể bạn đang cố gắng giải quyết và những vấn đề bạn gặp phải khi làm như vậy.

Cũng lưu ý SendStr, một loại là một chuỗi sở hữu hoặc một chuỗi tĩnh.
Chris Morgan

Câu trả lời:


135

Đã cập nhật cho Rust 1.0

Bạn không thể lấy &'static strtừ a Stringbởi vì Strings có thể không tồn tại trong suốt thời gian chương trình của bạn và đó là ý &'staticnghĩa của thời gian tồn tại. Bạn chỉ có thể lấy một lát cắt được tham số hóa theo Stringthời gian tồn tại của chính nó từ nó.

Để đi từ một Stringđến một phần, &'a strbạn có thể sử dụng cú pháp cắt:

let s: String = "abcdefg".to_owned();
let s_slice: &str = &s[..];  // take a full slice of the string

Ngoài ra, bạn có thể sử dụng thực tế Stringtriển khai Deref<Target=str>và thực hiện một khoản vay lại rõ ràng:

let s_slice: &str = &*s;  // s  : String 
                          // *s : str (via Deref<Target=str>)
                          // &*s: &str

Thậm chí còn có một cách khác cho phép tạo ra cú pháp ngắn gọn hơn nữa nhưng nó chỉ có thể được sử dụng nếu trình biên dịch có thể xác định kiểu đích mong muốn (ví dụ: trong các đối số hàm hoặc các ràng buộc biến được nhập rõ ràng). Nó được gọi là ép buộc deref và nó cho phép sử dụng &toán tử just và trình biên dịch sẽ tự động chèn một lượng *s thích hợp dựa trên ngữ cảnh:

let s_slice: &str = &s;  // okay

fn take_name(name: &str) { ... }
take_name(&s);           // okay as well

let not_correct = &s;    // this will give &String, not &str,
                         // because the compiler does not know
                         // that you want a &str

Lưu ý rằng mẫu này không phải là duy nhất cho String/ &str- bạn có thể sử dụng nó với mọi cặp loại được kết nối thông qua Deref, ví dụ, với CString/ CStrOsString/ OsStrtừ std::ffimô-đun hoặc PathBuf/ Pathtừ std::pathmô-đun.


29
Trong Rust 1.10 thay vì let s_slice: &str = &s[..];bạn chỉ có thể làm điều này:let s_slice: &str = s.as_str();
Shnatsel

3
Đôi khi, chuỗi gốc không đủ sống, chẳng hạn như trong một khối {...} khớp. Điều đó sẽ dẫn đến a 's' does not live long enough error.
Dereckson

41

Bạn có thể làm điều đó, nhưng nó liên quan đến việc rò rỉ bộ nhớ củaString . Đây không phải là điều bạn nên làm nhẹ nhàng. Bằng cách làm rò rỉ bộ nhớ của String, chúng tôi đảm bảo rằng bộ nhớ sẽ không bao giờ được giải phóng (do đó, rò rỉ). Do đó, bất kỳ tham chiếu nào đến đối tượng bên trong có thể được hiểu là có 'staticthời gian tồn tại.

fn string_to_static_str(s: String) -> &'static str {
    Box::leak(s.into_boxed_str())
}

fn main() {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).unwrap();
    let s: &'static str = string_to_static_str(s);
}

8
Stringđảm bảo rằng miễn là đối tượng chưa bị đánh rơi, bộ nhớ vẫn tồn tại. Vì mem::forgetđảm bảo rằng đối tượng sẽ không bao giờ bị loại bỏ, chúng tôi đảm bảo rằng tham chiếu đến đối tượng được chứa strsẽ không bao giờ không hợp lệ. Do đó, chúng tôi có thể khẳng định rằng đó là một 'statictham chiếu
oli_obk 22/02/16

1
Điều này cực kỳ hữu ích cho ứng dụng Rust của tôi, ứng dụng này cần phải ép buộc Stringthành một &'static strđể các mã thông báo được tạo từ bản gốc Stringsẽ có sẵn trên tất cả các chuỗi. Nếu không có điều này, trình biên dịch Rust sẽ phàn nàn rằng Stringvòng đời của tôi kết thúc ở cuối chức năng chính, điều này không đủ tốt vì nó không có sự 'staticđảm bảo.
mmstick

1
@mmstick: các giải pháp tốt hơn trong trường hợp đó sẽ được sử dụng crossbeamvà scoped đề
oli_obk

3
@mmstick: nếu bạn đặt toàn bộ ứng dụng của mình vào phạm vi crossbeam và tạo chuỗi bên ngoài phạm vi, bạn sẽ nhận được chính xác điều đó.
oli_obk

1
Câu trả lời này là tuyệt vời! Cả hai đều cho tôi biết cách tạo một lát chuỗi tĩnh và thuyết phục tôi không làm điều đó! Tôi đã chọn cấu trúc lại ứng dụng của mình để không sử dụng các lát chuỗi tĩnh ở rất nhiều nơi.
Paul Chernoch

22

Kể từ phiên bản Rust 1.26, có thể chuyển đổi a Stringthành &'static strmà không cần sử dụng unsafemã:

fn string_to_static_str(s: String) -> &'static str {
    Box::leak(s.into_boxed_str())
}

Điều này chuyển Stringthể hiện thành một hộp strvà ngay lập tức làm rò rỉ nó. Điều này giải phóng tất cả dung lượng dư thừa mà chuỗi hiện có thể chiếm.

Lưu ý rằng hầu như luôn có các giải pháp tốt hơn các đối tượng bị rò rỉ, ví dụ như sử dụng crossbeamthùng nếu bạn muốn chia sẻ trạng thái giữa các luồng.


2

TL; DR: bạn có thể nhận được &'static strtừ Stringmà bản thân nó có 'staticthời gian tồn tại.

Mặc dù các câu trả lời khác là đúng và hữu ích nhất, nhưng có một trường hợp cạnh (không hữu ích lắm), nơi bạn thực sự có thể chuyển đổi a Stringthành &'static str:

Thời gian tồn tại của tham chiếu phải luôn ngắn hơn hoặc bằng thời gian tồn tại của đối tượng được tham chiếu. Tức là đối tượng được tham chiếu phải tồn tại lâu hơn (hoặc bằng tuổi thọ) so với tham chiếu. Vì 'staticcó nghĩa là toàn bộ thời gian tồn tại của một chương trình, thời gian tồn tại lâu hơn không tồn tại. Nhưng một cuộc đời bình đẳng sẽ là đủ. Vì vậy, nếu một Stringcó thời gian tồn tại 'static, bạn có thể lấy &'static strtham chiếu từ nó.

Về mặt lý thuyết, việc tạo một statickiểu Stringđã trở nên khả thi với Rust 1.31 khi const fntính năng này được phát hành. Thật không may, hàm chỉ const trả lại một StringString::new()hiện nay, và nó vẫn còn đằng sau một cửa tính năng (như vậy Rust đêm là cần thiết cho bây giờ).

Vì vậy, đoạn mã sau thực hiện chuyển đổi mong muốn (sử dụng hàng đêm) ... và thực sự không có giá trị sử dụng thực tế nào ngoại trừ việc hoàn toàn cho thấy rằng nó có thể xảy ra trong trường hợp cạnh này.

#![feature(const_string_new)]

static MY_STRING: String = String::new();

fn do_something(_: &'static str) {
    // ...
}

fn main() {
    do_something(&MY_STRING);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.