對于每一個程序,字符串都是需要掌握的重要內容。由于Rust注重系統,所以它的字符串處理系統與其它語言有些許區別。每當你碰到一個可變大小的數據結構時,情況都會變得很微妙,而字符串正是可變大小的數據結構。這也就是說,Rust的字符串與一些像C這樣的系統編程語言也不相同。
讓我們深入細節。一個_字符串_是一串UTF-8字節編碼的Unicode量級值的序列。所有的字符串都確保是有效編碼的UTF-8序列。另外,字符串并不以null結尾并且可以包含null字節。
Rust有兩種主要的字符串類型:`&str`和`String`。
第一種是`&str`。這叫做_字符串片段_(_string slices_)。下面這個字面意思的string是`&str`類型的:
~~~
let string = "Hello there."; // string: &str
~~~
這個字符串是靜態分配的,也就是說它儲存在我們編譯好的程序中,并且整個程序的運行過程中一直存在。這個`string`綁定了一個靜態分配的字符串的引用。字符串片段是固定大小的并且不能改變。
一個`String`,相反,是一個在堆上分配的字符串。這個字符串可以增長,并且也保證是UTF-8編碼的。`String`通常通過一個字符串片段調用`to_string`方法轉換而來。
~~~
let mut s = "Hello".to_string(); // mut s: String
println!("{}", s);
s.push_str(", world.");
println!("{}", s);
~~~
`String`可以通過一個`&`強轉為`&str`:
~~~
fn takes_slice(slice: &str) {
println!("Got: {}", slice);
}
fn main() {
let s = "Hello".to_string();
takes_slice(&s);
}
~~~
把`String`當作`&str`是廉價的,不過從`&str`轉換到`String`涉及到分配內存。除非必要,沒有理由這樣做!
## 索引
因為字符串是有效UTF-8編碼的,它不支持索引:
~~~
let s = "hello";
println!("The first letter of s is {}", s[0]); // ERROR!!!
~~~
通常,用`[]`訪問一個數組是非常快的。不過,字符串中每個UTF-8編碼的字符可以是多個字節,你必須遍歷字符串來找到字符串的第N個字符。這是一個更昂貴的操作,而且我們不想被誤導。更進一步,Unicode實際上并沒有定義什么“字符”。我們可以選擇把字符串看作一個串獨立的字節,或者代碼點(codepoints):
~~~
let hachiko = "忠犬ハチ公";
for b in hachiko.as_bytes() {
print!("{}, ", b);
}
println!("");
for c in hachiko.chars() {
print!("{}, ", c);
}
println!("");
~~~
這會打印:
~~~
229, 191, 160, 231, 138, 172, 227, 131, 143, 227, 131, 129, 229, 133, 172,
忠, 犬, ハ, チ, 公,
~~~
如你所見,這里有比`char`更多的字節。
你可以這樣來獲取跟索引相似的東西:
~~~
let dog = hachiko.chars().nth(1); // kinda like hachiko[1]
~~~
這強調了我們不得不遍歷整個`char`的列表。
## 連接(Concatenation)
如果你有一個`String`,你可以在它后面接上一個`&str`:
~~~
let hello = "Hello ".to_string();
let world = "world!";
let hello_world = hello + world;
~~~
不過如果你有兩個`String`,你需要一個`&`:
~~~
let hello = "Hello ".to_string();
let world = "world!".to_string();
let hello_world = hello + &world;
~~~
這是因為`&String`可以自動轉換為一個`&str`。這個功能叫做[`Deref`轉換](http://doc.rust-lang.org/nightly/book/deref-coercions.html)。
- 前言
- 1.介紹
- 2.準備
- 2.1.安裝Rust
- 2.2.Hello, world!
- 2.3.Hello, Cargo!
- 3.學習Rust
- 3.1.猜猜看
- 3.2.哲學家就餐問題
- 3.3.其它語言中的Rust
- 4.高效Rust
- 4.1.棧和堆
- 4.2.測試
- 4.3.條件編譯
- 4.4.文檔
- 4.5.迭代器
- 4.6.并發
- 4.7.錯誤處理
- 4.8.外部語言接口
- 4.9.Borrow 和 AsRef
- 4.10.發布途徑
- 5.語法和語義
- 5.1.變量綁定
- 5.2.函數
- 5.3.原生類型
- 5.4.注釋
- 5.5.If語句
- 5.6.for循環
- 5.7.while循環
- 5.8.所有權
- 5.9.引用和借用
- 5.10.生命周期
- 5.11.可變性
- 5.12.結構體
- 5.13.枚舉
- 5.14.匹配
- 5.15.模式
- 5.16.方法語法
- 5.17.Vectors
- 5.18.字符串
- 5.19.泛型
- 5.20.Traits
- 5.21.Drop
- 5.22.if let
- 5.23.trait對象
- 5.24.閉包
- 5.25.通用函數調用語法
- 5.26.包裝箱和模塊
- 5.27.`const`和`static`
- 5.28.屬性
- 5.29.`type`別名
- 5.30.類型轉換
- 5.31.關聯類型
- 5.32.不定長類型
- 5.33.運算符和重載
- 5.34.`Deref`強制多態
- 5.35.宏
- 5.36.裸指針
- 6.Rust開發版
- 6.1.編譯器插件
- 6.2.內聯匯編
- 6.3.不使用標準庫
- 6.4.固有功能
- 6.5.語言項
- 6.6.鏈接參數
- 6.7.基準測試
- 6.8.裝箱語法和模式
- 6.9.切片模式
- 6.10.關聯常量
- 7.詞匯表
- 8.學院派研究
- 勘誤