Strings

See this chapter on YouTube

Rust memiliki 2 type strings yang umum: String dan &str. Apa perbedaannya?

  • &str adalah sebuah string yang simple. Jika Anda menulis let my_variable = "Hello, world!", Anda baru saja membuat &str. &str sangatlah cepat.
  • String adalah string yang agak rumit. Ia cenderung lambat, namun memiliki banyak kegunaan. String adalah pointer, dengan data yang ditaruh pada heap.

Perlu dicatat bahwa &str memiliki & dibagian depannya karena Anda perlu sebuah reference untuk menggunakan str. Hal itu dikarenakan oleh hal yang sebelumnya telah kita bahas: stack perlu tahu ukuran dari data. Oleh karena itu, kita berikan ia & yang membuat ia tahu ukurannya, dan voila, semuanya baik-baik saja. Dan juga, karena kita menggunakan & untuk berinteraksi dengan str, you don't own it (Anda tidak bisa memiliki valuenya, melainkan hanya sekedar meminjam untuk melihat valuenya). Sedangkan String adalah owned type. Secepatnya kita akan mempelajari tentang mengapa hal ini sangatlah penting untuk diketahui.

&str dan String keduanya menggunakan UTF-8. Sebagai contoh, Anda bisa menulis:

fn main() {
    let name = "서태지"; // Ini adalah nama Korea. Karakter Korea muncul tanpa ada masalah, karena &str menggunakan UTF-8.
    let other_name = String::from("Adrian Fahrenheit Țepeș"); // Ț dan ș pun adalah UTF-8.
}

Anda bisa melihat pada String::from("Adrian Fahrenheit Țepeș") bahwa sangatlah mudah membuat sebuah String dari &str. Kedua type ini sangat erat terkait satu sama lain, meskipun keduanya berbeda.

Bahkan kita juga bisa menuliskan emoji. Berterima kasihlah pada UTF-8. :D

fn main() {
    let name = "😂";
    println!("My name is actually {}", name);
}

Komputer Anda tentunya akan mencetak My name is actually 😂 kecuali command line di komputer Anda tidak bisa mencetaknya. Maka ia akan mencetak My name is actually �. Akan tetapi Rust tidak memiliki problem dengan emojis atau Unicode lainnya.

Untuk memastikan bahwa kita telah paham tentang &str, mari kita lihat alasan lain tentang mengapa kita menggunakan & untuk str.

  • str itu adalah dynamically sized type (dynamically sized = ukurannya bisa berubah-ubah). Contohnya, nama Korea "서태지" dan "Adrian Fahrenheit Țepeș" tentu memiliki ukuran yang tidak sama:
fn main() {

    println!("A String is always {:?} bytes. It is Sized.", std::mem::size_of::<String>()); // std::mem::size_of::<Type>() akan memberikan Anda informasi tentang ukuran yang digunakan oleh suatu type dalam satuan byte
    println!("And an i8 is always {:?} bytes. It is Sized.", std::mem::size_of::<i8>());
    println!("And an f64 is always {:?} bytes. It is Sized.", std::mem::size_of::<f64>());
    println!("But a &str? It can be anything. '서태지' is {:?} bytes. It is not Sized.", std::mem::size_of_val("서태지")); // std::mem::size_of_val() akan memberikan Anda informasi tentang ukuran yang digunakan oleh suatu variabel dalam satuan byte
    println!("And 'Adrian Fahrenheit Țepeș' is {:?} bytes. It is not Sized.", std::mem::size_of_val("Adrian Fahrenheit Țepeș"));
}

Beginilah hasilnya:

A String is always 24 bytes. It is Sized.
And an i8 is always 1 bytes. It is Sized.
And an f64 is always 8 bytes. It is Sized.
But a &str? It can be anything. '서태지' is 9 bytes. It is not Sized.
And 'Adrian Fahrenheit Țepeș' is 25 bytes. It is not Sized.

Ini sebabnya kita membutuhkan &, karena & menghasilkan pointer, dan Rust tahu ukuran dari pointer. Sehingga pointer ditaruh di stack. Jika kita menulis str saja, Rust tidak tahu apa yang harus dilakukan karena ia tidak tahu ukurannya.

Ada banyak cara untuk membuat String. Ini adalah beberapa caranya:

  • String::from("This is the string text"); Ini adalah cara membuat String yang mana mengambil text (&str) dan membuatnya menjadi String.
  • "This is the string text".to_string(). Ini adalah cara lain untuk mengubah &str menjadi String.
  • Macro format!. Mirip seperti println!, hanya saja, yang berbeda adalah ia akan membuat String daripada melakukan printing. Jadi, Anda bisa melakukan hal ini:
fn main() {
    let my_name = "Billybrobby";
    let my_country = "USA";
    let my_home = "Korea";

    let together = format!(
        "I am {} and I come from {} but I live in {}.",
        my_name, my_country, my_home
    );
}

Sekarang kita memiliki String yang bernama together, akan tetapi ia tidak diprint.

Cara lain untuk membuat String adalah menggunakan method .into(), akan tetapi ini agak sedikit berbeda karena .into() tidak hanya digunakan untuk membuat String. Beberapa type bisa dengan mudah dikonversi ke dan dari type yang lainnya menggunakan From dan .into(). Atau dengan kata lain, jika kita punya From, maka kita juga punya .into(). From sangatlah jelas karena kita telah mengetahui typenya: kita tahu bahwa String::from("Some str") adalah String yang dikonversi dari &str. Tapi, dengan .into(), terkadang compiler tidak tahu kita ingin mengubahnya menjadi type apa:

fn main() {
    let my_string = "Try to make this a String".into(); // ⚠️
}

Rust tidak tahu type apa yang Anda inginkan, karena banyak type bisa dibuat dari &str. Compiler akan menegur kita dengan berkata, "Aku bisa mengkonversi type &str ke banyak type lainnya. Anda mau yang mana?"

error[E0282]: type annotations needed
 --> src\main.rs:2:9
  |
2 |     let my_string = "Try to make this a String".into();
  |         ^^^^^^^^^ consider giving `my_string` a type

Untuk menghilangkan error tersebut, Anda bisa menggunakan cara seperti ini:

fn main() {
    let my_string: String = "Try to make this a String".into();
}

Voila! Akhirnya Anda bisa membuat String menggunakan .into().