Bir dizeyi bir & 'statik dizeye dönüştürme


92

Nasıl dönüştürebilirim Stringbir içine &str? Daha spesifik olarak, bunu lifetime ( ) strile bir a dönüştürmek istiyorum .static&'static str


Bu mümkün ya da arzu edilen görünmüyor. 'staticömür, dizenin asla ayrılmayacağı anlamına gelir, yani bir bellek sızıntısı. Bazıları &'static stryerine neden ihtiyacın var ? &'a str'a

3
O &'a str zamana dönüştürmek nasıl görünürdü ?
Christoph

Via as_slice. Hangi somut sorunu çözmeye çalıştığınızı ve bunu yaparken hangi problemlerle karşılaştığınızı anlatırsanız yardımcı olmak daha kolay olacaktır.

Ayrıca SendStr, sahip olunan bir dize veya statik bir dize olan bir türe de dikkat edin .
Chris Morgan

Yanıtlar:


134

Rust 1.0 için güncellendi

Sen alamıyor &'static strbir gelen Stringçünkü Stringsenin programın tüm hayatı ve ne olduğunu yıllardan için canlı olmayabilir &'staticömür anlamına gelir. Sadece Stringkendi yaşam süresine göre parametrelendirilmiş bir dilim alabilirsiniz .

StringBir dilime gitmek &'a striçin dilimleme sözdizimini kullanabilirsiniz:

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

Alternatif olarak, açık bir yeniden ödünç alma Stringuygulayan Deref<Target=str>ve gerçekleştiren gerçeğini kullanabilirsiniz :

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

Daha da kısa sözdizimine izin veren başka bir yol daha vardır, ancak bu yalnızca derleyici istenen hedef türünü belirleyebiliyorsa kullanılabilir (örneğin, işlev bağımsız değişkenlerinde veya açıkça yazılan değişken bağlamalarda). Buna deref zorlama denir ve sadece &operatörün kullanılmasına izin verir ve derleyici *bağlama göre uygun miktarda s'yi otomatik olarak ekler :

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

Bu model için benzersiz olmadığı Not String/ &strsen aracılığıyla bağlanan türleri her çifti ile kullanabilirsiniz - Derefile, örneğin, CString/ CStrve OsString/ OsStrdan std::ffimodül veya PathBuf/ Pathdan std::pathmodülü.


29
Rust 1.10'da let s_slice: &str = &s[..];sizin yerine şunu yapabilirsiniz:let s_slice: &str = s.as_str();
Shnatsel

3
Bazen, orijinal dize, bir eşleşme {...} bloğunda olduğu gibi yeterince yaşamaz. Bu bir 's' does not live long enough error.
Dereckson

42

Bunu yapabiliriz, ama bunun gerekli kıldığı hatırasını sızıntıString . Bu, hafifçe yapman gereken bir şey değil. Öğesinin belleğini sızdırarak, belleğin Stringasla serbest kalmayacağını (dolayısıyla sızıntıyı) garanti ederiz. Bu nedenle, iç nesneye yapılan herhangi bir referans, 'staticömür süresine sahip olarak yorumlanabilir .

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
Stringnesne düşmediği sürece hafızanın canlı kalacağını garanti eder. Yana mem::forgetnesne atılır asla teminat, biz içerdiği için referans olduğunu garanti strgeçersiz olmayacak. Böylece bir 'staticreferans olduğunu söyleyebiliriz
oli_obk

1
Bu zorlamak için gerekli benim Pas uygulama için son derece yararlı oldu Stringbir içine &'static strorijinalden oluşturdu simgeleri bunu Stringbütün parçacıkları arasında mevcut olacaktır. Bu olmadan, Rust derleyicisi bir ömrümün Stringana işlevin sonunda sona erdiğinden şikayet ederdi , bu da yeterince iyi değildi çünkü 'staticgarantisi yoktu .
mmstick

1
@mmstick: Bu durumda daha iyi çözüm, crossbeamkonuları kullanmak ve kapsamını sağlamak olacaktır
oli_obk

3
@mmstick: Tüm uygulamanızı bir çapraz kapsama yerleştirirseniz ve dizeyi kapsamın dışında oluşturursanız, tam olarak bunu elde edersiniz.
oli_obk

1
Bu cevap harika! Her ikisi de bana statik bir dizi diliminin nasıl hileli bir şekilde oluşturulacağını anlattı ve beni bunu yapmamaya ikna etti! Uygulamamı pek çok yerde statik dize dilimleri kullanmayacak şekilde yeniden düzenlemeyi seçtim.
Paul Chernoch

24

Pas sürümü 1.26 itibariyle, bir dönüştürmek mümkündür Stringiçin &'static strkullanmadan unsafekod:

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

Bu, Stringörneği bir kutuya dönüştürür strve hemen sızdırır. Bu, dizenin şu anda kaplayabileceği tüm fazla kapasiteyi serbest bırakır.

Sızdıran nesnelere göre hemen hemen her zaman tercih edilen çözümler olduğunu unutmayın, örneğin crossbeamdurumu iş parçacıkları arasında paylaşmak istiyorsanız sandığı kullanmak .


2

TL; DR: Bir alabilirsiniz &'static strbir gelen Stringkendisi a sahip olan'static ömrünü.

Diğer cevaplar doğru ve en kullanışlı olmasına rağmen, gerçekten bir dönüştürebilen bir (o kadar kullanışlı değil) kenarı durumda, orada Stringa kadar&'static str :

Bir referansın ömrü her zaman daha kısa veya referans verilen nesnenin yaşam süresine eşit olmalıdır. Yani referans verilen nesne referanstan daha uzun (veya eşit uzunlukta) yaşamalıdır. Yana 'staticbir programın aracı tüm ömrü, daha uzun bir kullanım ömrü yok. Ancak eşit bir ömür yeterli olacaktır. Öyleyse Stringbir ömür boyu 'staticvarsa,&'static str referans .

Bir statictür oluşturmak String, const fnözellik piyasaya sürüldüğünde teorik olarak Rust 1.31 ile mümkün hale geldi . Ne yazık ki, bir dönen sadece const işlevi Stringolduğunu String::new()şu anda ve bu (Pas gece şimdilik gereklidir böylece) bir özellik kapının arkasında hâlâ burada.

Dolayısıyla, aşağıdaki kod istenen dönüşümü yapar (gece kullanarak) ... ve aslında bu uç durumda mümkün olduğunu göstermenin tamlığı dışında pratik bir kullanımı yoktur.

#![feature(const_string_new)]

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

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

fn main() {
    do_something(&MY_STRING);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.