RUST 學(xué)習(xí)日記 第13課 ——字符串(一)

RUST 學(xué)習(xí)日記 第13課 ——字符串(一)


0x00 回顧與開篇

上節(jié)課講解了切片(Slice)、數(shù)組(Array)、向量(Vector)的區(qū)別??吹胶枚嗤瑢W(xué)給我反饋,說(shuō)可能有點(diǎn)兒晦澀難懂。那我在這里給你們吃一顆定心丸,你們可以先只了解有切片這個(gè)定義就可以了。這節(jié)課繼續(xù)講解一種重要數(shù)據(jù)類型——字符串(String)??梢赃@么說(shuō),在所有的程序中,大約有80%的代碼都是與字符串有關(guān)系,所以它很重要。

也許,了解Rust的字符串,你只看這篇文章就夠了。

0x01 字符串的定義

在Rust中有兩種字符串類型:

  • &str:原始的字符串類型str(發(fā)音:/st??r/),常被叫做字符串切片,它通常以不可變借用的形式出現(xiàn),即&str。它是一種固定長(zhǎng)度的字符串,不能隨意更改其長(zhǎng)度。咱們經(jīng)常寫的字符串字面量就是&str類型。
  • String:這種字符串類型是一種可變長(zhǎng)度的字符串,可以隨意更改它的長(zhǎng)度。String其實(shí)就是一個(gè)結(jié)構(gòu)體,它里面封裝了向量類型。這也很好理解它為什么是可變的了吧。下面是String在源碼中的定義:
image

0x02 字符串字面量(&str)

在第7課已經(jīng)提到過(guò)字面量了,這里單獨(dú)講下字符串字面量。字符串字面量它就是&str類型。

示例代碼如下:

    // 未聲明類型
    let hello1 = "hello study rust!";
    // 聲明類型
    let hello2: &str = "hello study rust!";
    println!("hello1 = {}", hello1);
    println!("hello2 = {}", hello2);
轉(zhuǎn)義

在字符串字面量中,英文雙引號(hào)需要通過(guò)\轉(zhuǎn)義。

示例代碼如下:

    let hello3 = "I bought a book called \"Rust\"";
    println!("hello3 = {}", hello3);

代碼運(yùn)行結(jié)果:

I bought a book called "Rust"
換行符

如果定義的字符串比較長(zhǎng),通常在代碼中習(xí)慣性的加上換行符,那么也會(huì)將換行符輸出。但是通常,咱們換行只是為了代碼美觀,這時(shí)如果在需要換行的地方以\結(jié)尾,則會(huì)忽略當(dāng)前行的換行符和下一行的開頭空白符。

示例代碼如下:

// 換行
    let hello4 = "My name is Betty, 18 years old. I like play piano very much and was awarded
    of a numbers of prizes for that.";
    println!("hello4 = {}", hello4);

    // 忽略換行符
    let hello5 = "My name is Betty, 18 years old. I like play piano very much and was awarded \
    of a numbers of prizes for that.";
    println!("hello5 = {}", hello5);

代碼運(yùn)行結(jié)果:

hello4 = My name is Betty, 18 years old. I like play piano very much and was awarded
    of a numbers of prizes for that.
hello5 = My name is Betty, 18 years old. I like play piano very much and was awarded of a numbers of prizes for that.
原始字符串(Raw String)

有的時(shí)候是不是感覺(jué)轉(zhuǎn)義其實(shí)是一個(gè)很煩的事情,尤其是在輸入windows文件路徑的時(shí)候。別著急,Rust提供了一種Raw String類型,字面翻譯是未經(jīng)處理的字符串,原始字符串。

Raw String定義:Raw String以小寫字面r為標(biāo)記,其中的所有反斜杠和空白符都會(huì)原樣的包含在字符串中,轉(zhuǎn)義符在其中無(wú)效。如果原始字符串中包含英文引號(hào),則需要在字符串的開頭和結(jié)尾添加#號(hào)標(biāo)記。(#號(hào)數(shù)量可自己定義,但是開頭和結(jié)尾的數(shù)量一定要相等。)

示例代碼如下:

// 測(cè)試轉(zhuǎn)義
    let raw_str = r"D:\study_rust\013\string";
    println!("raw_str = {}", raw_str);

    // 測(cè)試引號(hào)
    let raw_str_ref = r##"測(cè)試引號(hào)"英文引號(hào)",英文引號(hào)會(huì)原樣輸出!!"##;
    println!("raw_str_ref = {}", raw_str_ref);

代碼運(yùn)行結(jié)果:

raw_str = D:\study_rust\013\string
raw_str_ref = 測(cè)試引號(hào)"英文引號(hào)",會(huì)原樣輸出!!
字節(jié)字符串 (Byte String)

字節(jié)字符串就是前綴帶有b的字符串字面量,類似于在第7課中字節(jié)字符。字節(jié)字符串的是u8值(字節(jié))的切片,只能幫韓ASCII字符和\xHH轉(zhuǎn)義序列,其不能包含任何Unicode字符。

PS:它不支持在后面將要介紹的所有字符串的方法,其最像字符串的地方就是它的語(yǔ)法了。但是它支持上面介紹的跨行,轉(zhuǎn)義,原始字節(jié)字符串。其中,原始字節(jié)字符串以br開頭。

示例代碼如下:

    // 字節(jié)字符串
    let byte_str = b"a byte string!";
    println!("byte_str = {:#?}", byte_str);

    // 原始字節(jié)字符串
    let raw_byte_str = br#"it is a "raw byte string"."#;
    println!("raw_str_ref = {:#?}", raw_byte_str);

代碼運(yùn)行結(jié)果:

byte_str = [97, 32, 98, 121, 116, 101, 32, 115, 116, 114, 105, 110, 103, 33]
raw_str_ref = [105, 116, 32, 105, 115, 32, 97, 32, 34, 114, 97, 119, 32, 98, 121, 116, 101, 32, 115, 116, 114, 105, 110, 103, 34, 46]

看到上面的運(yùn)行結(jié)果了嗎?沒(méi)錯(cuò)不要驚訝,其實(shí)它實(shí)際上就是&[u8;N]——哈哈,這不就是上節(jié)課介紹的切片引用嗎。byte_str就是包含14個(gè)字節(jié)的數(shù)組的切片引用。

0x03 可變長(zhǎng)度字符串(String)

前面提到過(guò),String類似于Vec<T>,其本質(zhì)就是一個(gè)字段為Vec<u8>類型的結(jié)構(gòu)體。每個(gè)String都有在堆上分配的緩沖區(qū),不跟其它的String共享。當(dāng)String變量超出作用域后其緩沖區(qū)會(huì)自動(dòng)釋放,除非String的所有權(quán)發(fā)生轉(zhuǎn)移(有關(guān)所有權(quán)的知識(shí)點(diǎn)在后續(xù)章節(jié)介紹)。當(dāng)然String它在棧上也是由3部分組成,分別是指向堆上的字節(jié)序列的指針、記錄堆上字節(jié)序列的長(zhǎng)度、在堆上分配的容量。

創(chuàng)建字符串

創(chuàng)建字符串的常見的方式有三種:

1、使用String::new創(chuàng)建空的字符串。

let empty_string = String::new();

2、使用String::from通過(guò)字符串字面量創(chuàng)建字符串。實(shí)際上復(fù)制了一個(gè)新的字符串。

let rust_str = "rust";
let rust_string = String::from(rust_str);
  • 為什么是說(shuō)它是復(fù)制了一個(gè)新的字符串呢?

as_ptr()方法可以打印rust_strrust_string指向堆的內(nèi)存地址。

示例代碼如下:

println!("rust_str 字面量指向的地址 {:?}", rust_str.as_ptr());
println!("rust_string 指向的地址 {:?}", &rust_string.as_ptr());

代碼運(yùn)行結(jié)果(注:內(nèi)存地址每次運(yùn)行可能都不一致):

rust_str 字面量指向的地址 0x7ff61cac08a8
rust_string 指向的地址 0x164c4c7aa00

結(jié)果就是不一樣,他們指向堆的地址是兩個(gè)不同的地址。也就是說(shuō),在堆上有兩個(gè)地方保存了rust這個(gè)字符串。下節(jié)課會(huì)更詳細(xì)的講解String在內(nèi)存的表現(xiàn)形式。

3、使用字符串字面量的to_string將字符串字面量轉(zhuǎn)換為字符串。實(shí)際上復(fù)制了一個(gè)新的字符串

let s1 = "rust_to_string";
let s2 = s1.to_string();

to_string()實(shí)際上是封裝了String::from(),如下圖源碼:

image

這也間接解釋了to_string()為什么也是在堆上復(fù)制了一個(gè)新的字符串了。

PS:to_string()最早支持的版本是1.9.0。

0x06 小結(jié)

如果你對(duì)C++比較熟悉,那么你肯定知道在C++中存在兩種字符串類型,那么在Rust中也有類似的兩種字符串類型,本節(jié)簡(jiǎn)單介紹了String&str的這兩種類型的概念。簡(jiǎn)單介紹了String的三種創(chuàng)建方式和String字符串在內(nèi)存的形式如同向量一樣。是不是感覺(jué)還不是很懂,還是有點(diǎn)兒“懵”。它們到底是怎么保存的呢?String既然封裝了向量類型,那么它跟向量類型又存在什么區(qū)別呢?下節(jié)課詳細(xì)講解字符串在內(nèi)存中的表現(xiàn)形式。帶你徹底搞懂String&str

0x7 本節(jié)源碼

013 · StudyRust - 碼云 - 開源中國(guó) (gitee.com)

下節(jié)預(yù)告——字符串(二)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 簡(jiǎn)介 接上回 了解Rust 字符串首先要區(qū)分兩個(gè)概念,一個(gè)是字符串字面值,另外一個(gè)是字符串本身,這個(gè)在參數(shù)傳遞時(shí)是...
    kami1983閱讀 4,228評(píng)論 0 2
  • Rust語(yǔ)言教程(4) - 字符串 有了數(shù)組和向量的基礎(chǔ),我們?cè)賮?lái)看它的一個(gè)特例:字符串。 字符串有兩種表現(xiàn)形式...
    Jtag特工閱讀 3,822評(píng)論 0 1
  • 字符串是Python中常見的數(shù)據(jù)類型,在Python中,可以通過(guò)單引號(hào)或者雙引號(hào)來(lái)創(chuàng)建字符串,它們的作用是一樣的,...
    狗子渣渣閱讀 707評(píng)論 0 0
  • rust的字符串有兩種類型: str 和 String str 和 &str str 是被編碼成UTF-8的一個(gè)字...
    qiyinger閱讀 3,409評(píng)論 0 0
  • 看一看國(guó)內(nèi)都誰(shuí)在用 Rust,首先是就是字節(jié)跳動(dòng) 字符串在Rust是一個(gè)對(duì)象特殊類型,所以單拿出來(lái)進(jìn)行分享。可以將...
    zidea閱讀 2,007評(píng)論 0 2

友情鏈接更多精彩內(nèi)容