首頁 > 軟體

Rust字串字面值的一些經驗總結

2022-04-02 19:00:35

前言

Rust 中有兩種字串,String 和 &str,其中 String 可動態分配、修改,內部實現可以理解為 Vec<u8>,而 &str 是一個型別為 &[u8] 的切片。這兩種字串都只能儲存合法的 UTF-8 字元。

而對於非肉眼可辨識的 UTF-8 字元,則可以考慮使用如下型別:

  • 檔案路徑有專用的 Path 和 PathBuf 類可用。
  • 使用 Vec<u8> 和 &[u8]
  • 使用 OSString 和 &OSStr 和作業系統互動
  • 使用 CString 和 &CStr 和 C 庫互動

上面的第二種方法,就是常用的處理非 UTF-8 位元組流的方式,也就是使用 Vec<u8> 和 &[u8] ,其中我們也可以使用字面值來處理這兩種型別的資料,我們稱之為位元組字串字面值(byte string literals),其型別為 &[u8]。

字串字面值(String literals)

先來看一下字串字面值。

和其他語言一樣,用雙引號括起來就是一個字串,不過 Rust 的一個特點是字串可以跨行,即中間有回車也不會引起編譯或執行錯誤,在輸出的時候也會帶著裡面的換行符。

同樣,字串字面值裡面支援跳脫,比如想在裡面使用雙引號,該跳脫也會對換行符進行跳脫,比如下面這樣,在換行符前面使用 ,則該跳脫符、換行符以及下一行開頭的所有空格都將會被忽略:

let a = "foobar";
let b = "foo
         bar";
assert_eq!(a,b);

字串字面值除了支援常見的 對位元組(字元)進行跳脫,還支援對 Unicode 進行跳脫:

  • xHH: + 2位的十六進位制7位寬度位元組碼,這相當於等值的 ASCII 字元。
  • u{xxxx}:24位元長的16進位制,表示等值的 Unicode 字元。
  • n/r/t 表示 U+000A (LF), U+000D (CR) 和 U+0009 (HT)
  • \ 用來對 本身進行跳脫
  • 表示 Unicode U+0000 (NUL)

Raw 型別的字串字面值表示進行跳脫,也就是說字面值寫的是什麼內容,字串的值就是什麼。這種型別的字面值使用 r 以及若干 # 開頭進行定義,結尾需要相等數量的 #。

如下所示:

"foo"; r"foo";                     // foo
""foo""; r#""foo""#;             // "foo"

"foo #"# bar";
r##"foo #"# bar"##;                // foo #"# bar

"x52"; "R"; r"R";                 // R
"\x52"; r"x52";                  // x52

如果字串中有雙引號怎麼辦?因為 raw string 裡不能使用跳脫,所以 " 是肯定不行的。Rust 實際支援使用 r# 的方式來指定字串邊界。這個 # 就是跳脫的另一種實現方式,比如字串裡面有 4 個 #,那麼該字串可以用 r#####"abc####def"##### 來包圍起來,也就是比裡面的 # 多即可。

Byte string literals

Byte string 字面值使用 b"..." 以及衍生語法定義,其型別為 &[u8],這個和 &str 是完全不一樣的型別,所以有些在 &str 上能用的方法,在 &[u8] 上是用不了的。

比如:

// &[u8; 5]: [119, 111, 114, 108, 100]!
let world = b"world";
println!("Hello, {}!", world);

編譯會報錯,因為 &[u8] 沒有實現 std::fmt::Display:

29 |     println!("Hello, {}!", world);
   |                            ^^^^^ `[u8; 5]` cannot be formatted with the default formatter
   |

   = help: the trait `std::fmt::Display` is not implemented for `[u8; 5]`
   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
   = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)

Byte string 字面值也支援跳脫,但是需要注意它只支援位元組跳脫,不支援 Unicode 跳脫。

// 支援字元跳脫,輸出:Hello, Rust!
let escaped = b"x52x75x73x74 as bytes";

// 不支援 Unicode 跳脫,編譯錯誤:
// = help: unicode escape sequences cannot be used as a byte or in a byte string
let escaped = b"u{211D} is not allowed";
// Raw byte strings work just like raw strings
let raw_bytestring = br"u{211D} is not escaped here";
println!("{:?}", raw_bytestring);

// Converting a byte array to `str` can fail
if let Ok(my_str) = str::from_utf8(raw_bytestring) {
    println!("And the same as text: '{}'", my_str);
}

位元組字串也支援 raw 定義,和標準字串型別類似,使用 r 字首定義 raw byte string 字面值變數。

例如下面的例子中普通的位元組字串需要跳脫,raw 位元組字串就不需要使用 進行跳脫了。

b"foo"; br"foo";                     // foo
b""foo""; br#""foo""#;             // "foo"

b"foo #"# bar";
br##"foo #"# bar"##;                 // foo #"# bar

b"x52"; b"R"; br"R";                // R
b"\x52"; br"x52";                  // x52

總結

下面是剛才介紹的這幾種字串字面值定義的一個總結,列出了不同的定義方式和其含義。

符合    意義
“…”    字串字面值
r"…“, r#”…“#, r##”…“##, etc.    Raw 字串字面值,禁止跳脫
b"…“    位元組字串字面值,型別為 &[u8]
br"…“, br#”…“#, br##”…“##, etc.    Raw 位元組字串字面值
‘…’    字元字面值
b'…‘    ASCII位元組字面值

參考資料

到此這篇關於Rust字串字面值的文章就介紹到這了,更多相關Rust字串字面值內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com