Mengapa `find` mengambil parameter dengan referensi dan kemudian melakukan dereferensi? [duplikat]

Dalam cuplikan berikut, saya tidak mengerti mengapa penutupan mengambil parameternya s dengan referensi (&s), lalu melakukan dereferensi (*s):

fn main() {
    let needle = "list".to_string();
    let haystack = [
       "some".to_string(), 
        "long".to_string(),
        "list".to_string(),
        "of".to_string(),
        "strings".to_string(),
    ].to_vec();

    if let Some(str) = haystack.iter().find(|&s| *s == needle) {
        println!("{}", needle);
    } else {
        println!("Nothing there...");
    }
}

Apakah saya melewatkan sesuatu yang jelas?


person Pat Shaughnessy    schedule 01.03.2019    source sumber
comment
Akan lebih baik jika Anda sedikit lebih teliti dalam apa yang tampaknya membingungkan Anda. Penggunaan ||, tidak adanya return, fakta bahwa needle tidak ditangkap secara eksplisit (jadi bagaimana cara menangkapnya berdasarkan referensi atau nilai), ...   -  person Matthieu M.    schedule 01.03.2019
comment
Maaf: Yang membingungkan saya adalah penggunaan |&s| dalam parameter penutupan, dan sementara itu juga perlu menggunakan *s di dalam penutupan.   -  person Pat Shaughnessy    schedule 01.03.2019
comment
find(|&s| s == &needle) terlihat baik-baik saja bagiku   -  person Boiethios    schedule 01.03.2019
comment
Ah menarik, aku tidak memikirkan itu. Terima kasih. Apakah &needle yang dimaksud Matthieu dengan menangkap dengan referensi?   -  person Pat Shaughnessy    schedule 01.03.2019
comment
Saya pikir if haystack.contains(&needle) lebih idiomatis untuk Vec   -  person Stargateur    schedule 01.03.2019
comment
Hal ini secara khusus disebutkan dalam dokumentasi untuk metode yang Anda gunakan: Karena find() mengambil referensi, dan banyak iterator yang mengulangi referensi, hal ini mungkin menyebabkan situasi membingungkan di mana argumennya adalah referensi ganda. Anda dapat melihat efek ini pada contoh di bawah, dengan &&x.   -  person Shepmaster    schedule 01.03.2019


Jawaban (1)


Itu idiomatis. Beberapa orang mungkin memiliki preferensi yang berbeda mengenai apa yang sebenarnya didereferensikan kapan, dan/atau menggunakan .as_str() daripada melakukan dereferensi, namun secara umum tidak masalah.


Dalam kasus Anda .iter() mengulangi lebih dari Strings dengan referensi, sehingga memberikan &String elemen.

Kemudian .find() memberi Anda akses ke setiap elemen yang diulang dengan referensi lagi, sehingga Anda mendapatkan argumen &&String. Meskipun referensi referensi tersebut tidak ideal dalam kasus khusus ini, .find() adalah fungsi generik yang harus bekerja secara konsisten dengan tipe apa pun, sehingga hanya membuat referensi secara membabi buta.


Dalam argumen, &s adalah kebalikan dari pengambilan referensi. Sintaks argumen penutupan adalah:

|pattern: type|

dan tipenya opsional. Jadi yang tersisa hanyalah pola.

Penutupan Anda kemudian:

|pattern: &&String|

dan dengan pola Anda:

|&s: &&String| 

cocok dengan satu level &, sehingga Anda mendapatkan s menjadi &String.

Dan kemudian Anda ingin membandingkan s dari tipe &String dengan String. Untuk membandingkan tipe yang sama, Anda melakukan dereferensi &String hingga String dengan *s.

person Kornel    schedule 01.03.2019
comment
&s adalah kebalikan dari mengambil argumen dengan referensi — tidak, bukan itu. Masih memerlukan argumen dengan referensi, hanya langsung melakukan dereferensi. foo(bar: &String) dan foo(bar: String) berlawanan dalam dimensi ini. - person Shepmaster; 01.03.2019