TL; DR: Seseorang dapat menggunakan &str
, &[T]
atau &T
untuk mengizinkan kode yang lebih umum.
Salah satu alasan utama menggunakan a String
atau a Vec
adalah karena memungkinkan peningkatan atau penurunan kapasitas. Namun, saat Anda menerima referensi yang tidak dapat diubah, Anda tidak dapat menggunakan salah satu metode menarik tersebut di Vec
atau String
.
Menerima a &String
, &Vec
atau &Box
juga membutuhkan argumen untuk dialokasikan di heap sebelum Anda dapat memanggil fungsi tersebut. Menerima a &str
memungkinkan string literal (disimpan dalam data program) dan menerima &[T]
atau &T
mengizinkan array atau variabel yang dialokasikan tumpukan. Alokasi yang tidak perlu adalah hilangnya kinerja. Ini biasanya langsung terungkap saat Anda mencoba memanggil metode ini dalam pengujian atau main
metode:
awesome_greeting(&String::from("Anna"));
total_price(&vec![42, 13, 1337])
is_even(&Box::new(42))
Pertimbangan kinerja lainnya adalah itu &String
, &Vec
dan &Box
memperkenalkan lapisan tipuan yang tidak perlu karena Anda harus melakukan dereferensi &String
untuk mendapatkan String
dan kemudian melakukan dereferensi kedua untuk berakhir di &str
.
Sebagai gantinya, Anda harus menerima string slice ( &str
), slice ( &[T]
), atau hanya referensi ( &T
). A &String
, &Vec<T>
atau &Box<T>
akan secara otomatis dipaksa menjadi &str
, &[T]
atau &T
, masing-masing.
fn awesome_greeting(name: &str) {
println!("Wow, you are awesome, {}!", name);
}
fn total_price(prices: &[i32]) -> i32 {
prices.iter().sum()
}
fn is_even(value: &i32) -> bool {
*value % 2 == 0
}
Sekarang Anda dapat memanggil metode ini dengan kumpulan tipe yang lebih luas. Misalnya, awesome_greeting
dapat dipanggil dengan string literal ( "Anna"
) atau dialokasikan String
. total_price
bisa dipanggil dengan referensi ke array ( &[1, 2, 3]
) atau yang dialokasikan Vec
.
Jika Anda ingin menambah atau menghapus item dari String
atau Vec<T>
, Anda dapat menggunakan referensi yang dapat diubah ( &mut String
atau &mut Vec<T>
):
fn add_greeting_target(greeting: &mut String) {
greeting.push_str("world!");
}
fn add_candy_prices(prices: &mut Vec<i32>) {
prices.push(5);
prices.push(25);
}
Khusus untuk irisan, Anda juga dapat menerima &mut [T]
atau &mut str
. Ini memungkinkan Anda untuk mengubah nilai tertentu di dalam slice, tetapi Anda tidak dapat mengubah jumlah item di dalam slice (yang artinya sangat dibatasi untuk string):
fn reset_first_price(prices: &mut [i32]) {
prices[0] = 0;
}
fn lowercase_first_ascii_character(s: &mut str) {
if let Some(f) = s.get_mut(0..1) {
f.make_ascii_lowercase();
}
}
&str
lebih umum (seperti: memberlakukan lebih sedikit batasan) tanpa mengurangi kemampuan"? Juga: poin 3 seringkali tidak terlalu penting menurut saya. BiasanyaVec
s danString
s akan hidup di stack dan bahkan sering berada di dekat frame stack saat ini. Tumpukan biasanya panas dan dereferensi akan disajikan dari cache CPU.total_price(&prices[0..4])
tidak perlu mengalokasikan vektor baru untuk irisan.&str
dan mengapa (berasal dari Python, jadi saya biasanya tidak secara eksplisit berurusan dengan jenis). Menghapus semua itu dengan sempurnaSelain jawaban Shepmaster , alasan lain untuk menerima a
&str
(dan yang serupa&[T]
dll) adalah karena semua jenis lain selainString
dan&str
itu juga memuaskanDeref<Target = str>
. Salah satu contoh yang paling menonjol adalahCow<str>
, yang memungkinkan Anda menjadi sangat fleksibel tentang apakah Anda berurusan dengan data yang dimiliki atau dipinjam.Jika Anda memiliki:
Tetapi Anda harus menyebutnya dengan
Cow<str>
, Anda harus melakukan ini:Saat Anda mengubah tipe argumen menjadi
&str
, Anda dapat menggunakan denganCow
mulus, tanpa alokasi yang tidak perlu, seperti denganString
:Menerima
&str
membuat pemanggilan fungsi Anda lebih seragam dan nyaman, dan cara "termudah" sekarang juga paling efisien. Contoh ini juga akan berfungsi denganCow<[T]>
dll.sumber