Rust 語言學習之旅(3)

banq發表於2022-09-29

字串常量(String Literals)
字串常量(String Literals)採用 Unicode 編碼(注:下文提及的 utf-8 為 Unicode 的一部分)。
字串常量的型別為 &'static str:

  • & 意味著該變數為對記憶體中資料的引用,沒有使用 &mut 代表編譯器將不會允許對該變數的修改
  • 'static 意味著字串資料將會一直儲存到程式結束(它不會在程式執行期間被釋放(drop))
  • str 意味著該變數總是指向一串合法的 utf-8 位元組序列。

記憶體細節:
  • Rust 編譯器可能會將字串儲存在程式記憶體的資料段中。


fn main() {
    let a: &'static str = "你好 ";
    println!("{} {}", a, a.len());
}


跳脫字元
有些字元難以使用可視字元表示,這時可透過跳脫字元來表示這些字元。
Rust 支援類 C 語言中的常見跳脫字元;
  • \n - 換行符
  • \r - 回車符(回到本行起始位置)
  • \t - 水平製表符(即鍵盤 Tab 鍵)
  • \\ - 代表單個反斜槓 \
  • \0 - 空字元(null)
  • \' - 代表單引號 '

完整的跳脫字元表在這

fn main() {
    let a: &'static str = "Ferris 說:\t\"你好\"";
    println!("{}",a);
}


多行字串常量
Rust 中字串預設支援分行。
使用 \ 可以使多行字串不換行。

fn main() {
    let haiku: &'static str = "
        我寫下,擦掉,
        再寫,再擦,
        然後一朵罌粟花開了。
        - 葛飾北齋";
    println!("{}", haiku);
    
    
    println!("你好 \
    世界"); // 注意11行 世 字前面的空格會被忽略
}


原始字串常量
原始字串支援寫入原始的文字而無需為特殊字元轉義,因而不會導致可讀性下降(如雙引號與反斜槓無需寫為 \" 和 \\),只需以 r#" 開頭,以 "# 結尾。

fn main() {
    let a: &'static str = r#"
        <div class="advice">
            原始字串在一些情景下非常有用。
        </div>
        "#;
    println!("{}", a);
}


檔案中的字串常量
如果你需要使用大量文字,可以嘗試用宏 include_str! 來從本地檔案中匯入文字到程式中:
let hello_html = include_str!("hello.html");

字串片段(String Slice)
字串片段是對記憶體中位元組序列的引用,而且這段位元組序列必須是合法的 utf-8 位元組序列。
str 片段的字串片段(子片段),也必須是合法的 utf-8 位元組序列。
&str 的常用方法:
  • len 獲取字串常量的位元組長度(不是字元長度)。
  • starts_with/ends_with 用於基礎測試。
  • is_empty 長度為 0 時返回 true。
  • find 返回 Option<usize>,其中的 usize 為匹配到的第一個對應文字的索引值。


fn main() {
    let a = "你好 ";
    println!("{}", a.len());
    let first_word = &a[0..6];
    let second_word = &a[7..11];
    // let half_crab = &a[7..9]; 報錯
    // Rust 不接受無效 unicode 字元構成的片段
    println!("{} {}", first_word, second_word);
}


Char
為了解決使用 Unicode 帶來的麻煩,Rust 提供了將 utf-8 位元組序列轉化為型別 char 的 vector 的方法。
每個 char 長度都為 4 位元組(可提高字元查詢的效率)。

fn main() {
    // 收集字元並轉換為型別為 char 的 vector
    let chars = "你好 ".chars().collect::<Vec<char>>();
    println!("{}", chars.len()); // 結果應為 4
    // 由於 char 為 4 位元組長,我們可以將其轉化為 u32
    println!("{}", chars[3] as u32);
}


字串(String)
字串String 是一個結構體,其持有以堆(heap)的形式在記憶體中儲存的 utf-8 位元組序列。
由於它以堆的形式來儲存,字串可以延長、修改等等。這些都是字串常量(string literals)無法執行的操作。
常用方法:

  • push_str 用於在字串的結尾新增字串常量(&str)。
  • replace 用於將一段字串替換為其它的。
  • to_lowercase/to_uppercase 用於大小寫轉換。
  • trim 用於去除字串前後的空格。

如果字串String 被釋放(drop)了,其對應的堆記憶體片段也將被釋放。
字串String 可以使用 + 運算子來在其結尾處連線一個 &str 並將其自身返回。但這個方法可能並不像你想象中的那麼人性化。

fn main() {
    let mut helloworld = String::from("你好");
    helloworld.push_str(" 世界");
    helloworld = helloworld + "!";
    println!("{}", helloworld);
}


將文字作為函式的引數
字串常量(String literals)和字串(String)一般以字串片段(string slice)的形式傳遞給函式。這給許多場景提供了充足的靈活性,因為所有權並未被傳遞。

fn say_it_loud(msg:&str){
    println!("{}!!!",msg.to_string().to_uppercase());
}

fn main() {
    // say_it_loud can borrow &'static str as a &str
    say_it_loud("你好");
    // say_it_loud can also borrow String as a &str
    say_it_loud(&String::from("再見"));
}

concat 和 join 可以以簡潔而有效的方式構建字串。
fn main() {
    let helloworld = ["你好", " ", "世界", "!"].concat();
    let abc = ["a", "b", "c"].join(",");
    println!("{}", helloworld);
    println!("{}",abc);
}

字串格式化
宏 format! 可用於建立一個使用佔位符的引數化字串。(例:{})
format! 和 println! 生成的引數化字串相同,只是 format! 將其返回而 println! 將其列印出來。
這個函式涉及的內容太過廣泛,因而不可能在 Rust 語言之旅 中詳細介紹, 如需瞭解完整的內容可看這裡

fn main() {
    let a = 42;
    let f = format!("生活訣竅: {}",a);
    println!("{}",f);
}


許多型別都可以透過 to_string 轉換為字串。
而泛型函式 parse 則可將字串或是字串常量轉換為其它型別,該函式會返回 Result 因為轉換有可能失敗。

fn main() -> Result<(), std::num::ParseIntError> {
    let a = 42;
    let a_string = a.to_string();
    let b = a_string.parse::<i32>()?;
    println!("{} {}", a, b);
    Ok(())
}

相關文章