Rust'un 'String` ve `str` arasındaki farklar nelerdir?


419

Rust neden var Stringve str? Arasındaki farklar nelerdir Stringve str? Bir kullanır zaman Stringyerine strtersi ve yardımcısı? Bunlardan biri kullanımdan kaldırılıyor mu?

Yanıtlar:


489

Stringdinamik yığın dize türüdür, örneğin Vec: dize verilerinize sahip olmanız veya değiştirmeniz gerektiğinde kullanın.

str, bellekte bir yerde dinamik uzunluktaki değişmez 1 UTF-8 baytlık bir dizidir. Boyut bilinmediği için, sadece işaretçi ile başa çıkabilir. Bu, stren yaygın olarak 2'nin şu şekilde göründüğü anlamına gelir &str: normalde "dize dilimi" veya yalnızca "dilim" olarak adlandırılan bazı UTF-8 verilerine başvuru. Dilim yalnızca bazı verilerin görünümüdür ve bu veriler herhangi bir yerde olabilir, ör.

  • Statik depolamada : bir dize hazır bilgisi "foo"a &'static str. Veriler yürütülebilir dosyaya sabit kodlanır ve program çalıştırıldığında belleğe yüklenir.
  • Bir yığın İçinde tahsisString : Stringdereferences bir karşı &strbakış arasında String'in verilerine.
  • Yığında : örn., Yığınla ayrılmış bir bayt dizisi oluşturur ve ardından bu verilerin&str bir görünümünü aşağıdaki gibi alır :

    use std::str;
    
    let x: &[u8] = &[b'a', b'b', b'c'];
    let stack_str: &str = str::from_utf8(x).unwrap();
    

Özet olarak, Stringsahip olunan dize verilerine ihtiyacınız varsa kullanın (dizeleri diğer iş parçacıklarına geçirmek veya çalışma zamanında oluşturmak gibi) ve &stryalnızca bir dize görünümüne ihtiyacınız varsa kullanın .

Bu, bir vektör Vec<T>ile bir dilim arasındaki ilişkiye özdeştir ve genel tipler için &[T]by-value Tve by-reference arasındaki ilişkiye benzer &T.


1 A strsabit uzunluktadır; sonuna kadar bayt yazamaz veya sondaki geçersiz bayt bırakamazsınız. UTF-8 değişken genişlikli bir kodlama olduğundan, bu durum tüm strdurumlarda etkili bir şekilde değişmez olmaya zorlar . Genel olarak, mutasyon öncekinden daha fazla veya daha az bayt yazmayı gerektirir (örneğin bir a(1 bayt) yerine ä(2+ bayt) koymak için daha fazla yer açmak gerekir str). Bir yerinde değişiklik yapabilen &str, çoğunlukla yalnızca ASCII karakterlerini işleyen belirli yöntemler vardır make_ascii_uppercase.

2 Dinamik olarak boyutlandırılmış türler , Rc<str>Rust 1.2'den bu yana UTF-8 bayt olarak sayılan bir referans dizisi gibi şeylere izin verir . Rust 1.21 bu tiplerin kolayca oluşturulmasını sağlar.


10
"UTF-8 bayt dizisi ( bilinmeyen uzunlukta )" - bu güncel değil mi? Docs "Bir söylemek &striki bileşenden oluşur: Bazı bayta bir işaretçi ve bir uzunluğa."
mrec

11
Eski değil (bu temsil oldukça istikrarlıydı), sadece biraz kesin değil: statik olarak bilinmemektedir, aksine, diyelim ki [u8; N],.
huon

2
mrec derleme zamanında bilinmemektedir, örneğin bir yığın çerçeve oluştururken boyutuyla ilgili varsayımlar yapılamaz. Bu nedenle, neden bir referans derleme zamanında bilinen bir boyut olan bir referans olarak kabul edilir, bu da bir işaretçinin boyutu.
Sekhat

1
Güncelleme: Rc<str>ve Arc<str>artık standart kütüphane aracılığıyla kullanılabilir.
Centril

1
@cjohansson Statik olarak tahsis edilen nesneler normalde ne yığında ne de yığınta, ancak kendi bellek bölgelerinde depolanır.
Brennan Vincent

96

Bir C ++ arka plan var ve çok Stringve &strC ++ açısından düşünmek için yararlı buldum :

  • Bir Rust Stringa std::string; hafızanın sahibidir ve hafızayı yönetmenin kirli işini yapar.
  • Rust &str, char*(ama biraz daha sofistike) gibidir; bizi içeriğinin bir göstergesini alabileceğiniz şekilde bir yığının başlangıcına yönlendirir std::string.

İkisi de yok olacak mı? Ben öyle düşünmüyorum. İki amaca hizmet ederler:

Stringtamponu tutar ve kullanımı çok pratiktir. &strhafiftir ve dizelere "bakmak" için kullanılmalıdır. Yeni bellek ayırmaya gerek kalmadan parçaları arayabilir, bölebilir, ayrıştırabilir ve hatta değiştirebilirsiniz.

&strbir Stringdize değişmezine işaret edebileceği için a'nın içine bakabilir . Aşağıdaki kodun değişmez dizeyi Stringyönetilen belleğe kopyalaması gerekir :

let a: String = "hello rust".into();

Aşağıdaki kod, hazır bilginin kendisini kopya olmadan kullanmanızı sağlar (salt okunur)

let a: &str = "hello rust";

12
string_view gibi mi?
Abhinav Gauniyal

1
Evet, string_view gibi ancak dile özgü ve uygun şekilde ödünç alındı.
locka

41

str, yalnızca &strbir dize dilimi, UTF-8 bayt dizisine başvuru olarak kullanılır.

Stringeskiden ne ~strbir growable, sahip olunan UTF-8 bayt dizisi.


Teknik olarak, eskiden ~strşimdiBox<str>
jv110

3
@ jv110: hayır, çünkü ~stryetiştirilebilir Box<str>olmasa da yetiştirilebilirdi. (Bu ~strve ~[T]diğer tüm ~nesnelerin aksine büyülü bir şekilde büyüyebilirdi, tam olarak neden Stringve Vec<T>tanıtıldı, böylece kurallar basit ve tutarlıydı.)
Chris Morgan

18

Aslında tamamen farklılar. Öncelikle, a strbir tür düzey şeyden başka bir şey değildir; dinamik olarak boyutlandırılmış bir tür (DST) olduğu için yalnızca tür düzeyinde düşünülebilir. Alınan boyut strderleme zamanında bilinemez ve çalışma zamanı bilgilerine bağlıdır - derleyicinin derleme zamanında her değişkenin boyutunun ne olduğunu bilmesi gerekir. A strkavramsal olarak sadece u8geçerli bir UTF-8 oluşturduğunu garanti eden bir bayt dizisidir. Sıra ne kadar büyük? Hiç kimse çalışma zamanına kadar bilmiyor, bu nedenle bir değişkende saklanamıyor.

İlginç olan bir olmasıdır &stra veya başka bir işaretçi strbeğendiniz Box<str> yapar zamanında mevcuttur. Bu sözde "şişman işaretçi" dir; ekstra bilgi içeren bir işaretçi (bu durumda işaret ettiği şeyin boyutu), bu yüzden iki kat daha büyük. Aslında a &str, a'ya oldukça yakındır String(ancak a'ya değil &String). A &striki kelimedir; a'nın ilk baytına bir işaretçi strve kaç bayt uzunluğunu açıklayan başka bir sayı str.

Söylenenlerin aksine, stra'nın değişmez olması gerekmez. Eğer &mut strözel bir işaretçi olarak alabilirsiniz str, onu değiştirebilir ve onu değiştiren tüm güvenli fonksiyonlar UTF-8 kısıtlamasının desteklendiğini garanti eder, çünkü bu ihlal edilirse kütüphane bu kısıtlamanın doğru ve kontrol etmez.

Öyleyse a Stringnedir? Bu üç kelime; iki ile aynıdır, &strancak stryığın üzerinde arabellek kapasitesi olan , her zaman yığın üzerinde olan (a strmutlaka yığın üzerinde değildir) üçüncü bir sözcük ekler ve doldurmadan önce yeniden ayırması gerekir. Stringtemelde sahibi bir strdedikleri gibi; onu kontrol eder ve yeniden boyutlandırabilir ve uygun gördüğünde yeniden tahsis edebilir. Yani bir Stringşekilde daha yakın bir söylenen &strbir daha str.

Başka bir şey bir Box<str>; Bu aynı zamanda a strve çalışma zamanı temsiliyle aynıdır, &strancak bunun straksine de sahip &strdeğildir , ancak yeniden boyutlandırılamaz çünkü kapasitesini bilmez, bu nedenle temel Box<str>olarak bir Stringyeniden boyutlandırılamayan sabit uzunluk olarak görülebilir ( her zaman Stringyeniden boyutlandırmak istiyorsanız bir dönüştürün ).

UTF-8 kısıtlaması arasında [T]ve Vec<T>dışında çok benzer bir ilişki vardır ve boyutu dinamik olmayan herhangi bir türü tutabilir.

Kullanımı strtürü düzey ile jenerik soyutlamalar oluşturmak için çoğunlukla üzerinde &str; özellikleri rahatça yazabilmek için tür düzeyinde bulunur. Teoride str, tipik bir şeyin var olmasına gerek yoktu ve sadece &strbu, şimdi genel olabilecek çok fazla kodun yazılması gerektiği anlamına geliyordu.

&strStringkopyalamak zorunda kalmadan birden çok farklı alt dizeye sahip olabilmek için çok kullanışlıdır ; gibi bir sözü String sahibistr yönettiği öbek üzerinde ve yalnızca bir alt dize oluşturmak eğer Stringyeni ile Stringo Rust her şeyi okunur bellek güvenliği ile başa çıkmak için tek sahibi olabilir çünkü kopyalanan etmesi gerekir. Örneğin, bir dizeyi dilimleyebilirsiniz:

let string: String   = "a string".to_string();
let substring1: &str = &string[1..3];
let substring2: &str = &string[2..4];

strAynı dizginin iki farklı alt dizesi var. yığın üzerinde stringgerçek tam strtampon sahip olan ve &stralt dizeleri yığın üzerinde bu tampon sadece yağ işaretçileridir.


4

std::Stringbasitçe bir vektörüdür u8. Tanımını kaynak kodunda bulabilirsiniz . Öbek tahsis edilmiş ve yetiştirilebilir.

#[derive(PartialOrd, Eq, Ord)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct String {
    vec: Vec<u8>,
}

strdize dilimi olarak da adlandırılan ilkel bir türdür . Dize diliminin boyutu sabittir. Gibi bir hazır bilgi dizesi let test = "hello world"vardır &'static strtürü. teststatik olarak tahsis edilen dizeye bir referanstır. &strörneğin değiştirilemez

let mut word = "hello world";
word[0] = 's';
word.push('\n');

strdeğiştirilebilir dilim var &mut str, örneğin: pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str)

let mut s = "Per Martin-Löf".to_string();
{
    let (first, last) = s.split_at_mut(3);
    first.make_ascii_uppercase();
    assert_eq!("PER", first);
    assert_eq!(" Martin-Löf", last);
}
assert_eq!("PER Martin-Löf", s);

Ancak UTF-8'deki küçük bir değişiklik bayt uzunluğunu değiştirebilir ve bir dilim başvurusunu yeniden tahsis edemez.


0

Kolay bir deyişle, Stringveri tipi yığın üzerinde depolanır (tıpkı gibi Vec) ve bu konuma erişiminiz vardır.

&strbir dilim türüdür. Bu String, öbek içinde zaten mevcut olan bir yere atıfta bulunduğu anlamına gelir .

&strçalışma zamanında herhangi bir ayırma yapmaz. Yani, hafıza nedenlerden dolayı kullanabileceğiniz &strüzerinde String. Ancak, kullanırken &straçık yaşamlarla uğraşmanız gerekebileceğini unutmayın .


1
yığın içinde bir yerde - bu tamamen doğru değil.
Shepmaster

Demek olmasıydı strolduğunu viewzaten mevcut Stringyığın.
00imvj00

1
Ne demek istediğini anlıyorum ve bunun tamamen doğru olmadığını söylüyorum. "Öbek" ifadenin zorunlu bir parçası değildir.
Shepmaster

-1

C # ve Java kullanıcıları için:

  • Pas ' String===StringBuilder
  • Rust'un &str === (değişmez) dizesi

&strBir dize görünümü olarak düşünmek istiyorum, Java / C # 'de değiştirilemeyen bir staj dizisi gibi, sadece yeni bir tane oluşturun.


1
Java / C # dizeleri ve Rust dizeleri arasındaki en büyük fark, Rust'un dizginin doğru unicode olmasını garantilemesidir, çünkü bir dizedeki üçüncü karakterin elde edilmesi sadece "abc" den daha fazla düşünmeyi gerektirir [2]. (Çok dilli bir dünyada yaşadığımız düşünüldüğünde, bu iyi bir şeydir.)
Sincap

Bu yanlış . Değişebilirlik konusu zaten en çok oylanan cevapta ele alınmış; daha fazla bilgi edinmek için lütfen okuyun.
Shepmaster

-5

İşte hızlı ve kolay bir açıklama.

String- Büyüyen, sahip olunan öbek tahsisli veri yapısı. A zorlanabilir &str.

str- (şimdi, Rust geliştikçe) öbekte veya ikili dosyada yaşayan mutable, sabit uzunlukta dizedir. Yalnızca, strbir dize dilimi görünümü aracılığıyla ödünç alınmış bir tür olarak etkileşimde bulunabilirsiniz &str.

Kullanımla ilgili hususlar:

StringBir dizeye sahip olmak veya onu değiştirmek isteyip istemediğinizi (dizeyi başka bir diziye geçirmek vb.) Tercih edin.

&strBir dizenin salt okunur bir görünümüne sahip olmayı tercih edin.


Bu yanlış . Değişebilirlik konusu zaten en çok oylanan cevapta ele alınmış; daha fazla bilgi edinmek için lütfen okuyun.
Shepmaster
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.