字符串和切片
切片
切片的作用是允許你引用集合中部分連續的元素序列,而不是引用整個集合。
例如:
let s = String::from("hello world");let hello = &s[0..5]; // 切片 [0,5) 等效于&s[..5]
let world = &s[6..11]; // 切片 [6,11) 等效于&s[6..]
// 完整的s,&s[..]
注意,方括號中的數字是字節,如果字符是多字節的(如漢字),這時如果切片沒有落在兩個字符之間,程序就會崩潰(漢字是三個字節,切片0-2就會崩潰)
字符串的切片類型是 &str,i32數組的切片類型是 &[i32]
這樣一段代碼:let s = "Hello world!";
, s 是個切片類型,實際上代碼為:let s: &str = "Hello world!"
字符串
Rust中字符是 Unicode 類型。內存占用 從1 - 4 個字節空間。
Rust中常用的字符串類型有 str / String,str硬編碼不可變,String可變。
// &str --> String
String::from("Hello world");
"hello world".to_string();// String --> &str
&s;
操作字符串
let mut s = String::from("Hello ");
// 追加字符串
s.push_str("rust");
// 追加字符
s.push('!');
// 插入字符
s.insert(5, ',');
// 插入字符串
s.insert_str(6, " I like");// 替換
// replace 適用于 String 和 &str,替換所有,返回一個新字符串,而不是操作原來的字符串
let new_string_replace = string_replace.replace("rust", "RUST");
// replacen 適用于 String 和 &str, 替換指定個數,返回一個新字符串,而不是操作原來的字符串
let new_string_replacen = string_replace.replacen("rust", "RUST", 1);
// replace_range 適用于 String,替換指定范圍字符串,操作原來的字符串
string_replace_range.replace_range(7..8, "R");// 刪除
// 均是操作原來的字符串
// pop 刪除并返回最后一個字符
let p1 = string_pop.pop();
// remove 刪除并返回指定位置字符
string_remove.remove(0);
// truncate 刪除指定位置到結尾
string_truncate.truncate(3);
// clear 清空字符串
string_clear.clear();// 連接
// + += ,右面必須是字符串的切片引用類型,相當于調用std::string add(),返回一個新字符串
let result = string_append + &string_rust;
// format!
let s = format!("{} {}!", s1, s2);
遍歷字符串
// 以 unicode 字符方式遍歷字符串
for c in "中國人".chars() {println!("{}", c);
}
元組
元組是由多種類型組合到一起形成的,因此它是復合類型,元組的長度是固定的,元組中元素的順序也是固定的。
fn main() {let tup: (i32, f64, u8) = (500, 6.4, 1);
}
使用元組:
fn main() {let tup = (500, 6.4, 1);// 模式匹配let (x, y, z) = tup;println!("The value of y is: {}", y);// .let five_hundred = x.0;let six_point_four = x.1;// 函數let s1 = String::from("hello");let (s2, len) = calculate_length(s1);
}fn calculate_length(s: String) -> (String, usize) {let length = s.len(); // len() 返回字符串的長度(s, length)
}
結構體
使用
結構體的定義:
struct User {active: bool,username: String,email: String,sign_in_count: u64,
}
結構體的創建和使用:
// 每個都需要初始化,順序可以打亂
let mut user1 = User {email: String::from("someone@example.com"),username: String::from("someusername123"),active: true,sign_in_count: 1,
};// 訪問字段,
// **必須要將結構體實例聲明為可變的,才能修改其中的字段,Rust 不支持將某個結構體某個字段標記為可變。**
user1.email = String::from("anotheremail@example.com");// 簡化創建
fn build_user(email: String, username: String) -> User {User {email,username,active: true,sign_in_count: 1,}
}// 更新
let user2 = User {email: String::from("another@example.com"),..user1 // 注意 username 發生了所有權轉移,不能再被user1使用
};
內存排列
struct File {name: String,data: Vec<u8>,
}
內存結構:
元組結構體
元組結構體的字段沒有名稱:
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
使用的使用可以直接用 x,y,z / r,g,b
單元結構體
單元結構體沒有任何字段和屬性
struct AlwaysEqual;let subject = AlwaysEqual;// 我們不關心 AlwaysEqual 的字段數據,只關心它的行為,因此將它聲明為單元結構體,然后再為它實現某個特征
impl SomeTrait for AlwaysEqual {}
結構體的所有權
如果你想在結構體中使用一個引用,就必須加上生命周期,否則就會報錯!
生命周期篇再寫。
打印
-
使用 #[derive(Debug)] 來打印結構體信息。
println!("{:?}",struct);
dbg!(&struct);
-
也可以實現 Display 特征打印信息(類似 toString() 方法)
println!("{}",struct);
枚舉
使用:
可以向其他語言一樣直接使用,也可以為其關聯數據信息
// enum PokerSuit {
// Clubs,
// Spades,
// Diamonds,
// Hearts,
// }enum PokerCard {Clubs(u8),Spades(u8),Diamonds(u8),Hearts(u8),
}fn main() {let c1 = PokerCard::Spades(5);let c2 = PokerCard::Diamonds(13);
}
更為復雜的:
enum Message {Quit,Move { x: i32, y: i32 },Write(String),ChangeColor(i32, i32, i32),
}fn main() {let m1 = Message::Quit;let m2 = Message::Move{x:1,y:1};let m3 = Message::ChangeColor(255,255,0);
}
使用Option枚舉處理空值
在rust中使用Option枚舉來處理對象為空的情況(null):
enum Option<T> {Some(T),None,
}
使用的使用將值存入 Some<T> 中,這樣在使用變量的時候因為不能直接使用 Option,所以需要將值取出來再用。而取出來的時候需要判斷值不是Option::None才能用,相當于變相強制進行了判空操作,放置了空指針異常。
數組
在Rust中有兩種數組,一種是長度固定嗎,速度快的 array,一種是長度動態,性能較低的 vector。
array存儲在棧上,vector存儲在堆上。
array
使用:
fn main() {// 1.定義// let a: [i32; 5] = [1, 2, 3, 4, 5]; 聲明類型let a = [1, 2, 3, 4, 5];// 重復:5個3let a = [3; 5]; // 非基礎元素// let array = [String::from("rust is good!"); 8]; × 不能深拷貝let array: [String; 8] = std::array::from_fn(|i| String::from("rust is good!"));// 2.訪問let first = a[0]; // 獲取a數組第一個元素
}
數組切片
- 創建切片的代價非常小,因為切片只是針對底層數組的一個引用
- 切片類型[T]擁有不固定的大小,而切片引用類型&[T]則具有固定的大小,因為 Rust 很多時候都需要固定大小數據類型,因此&[T]更有用,
&str
字符串切片也同理
let a: [i32; 5] = [1, 2, 3, 4, 5];let slice: &[i32] = &a[1..3]; // 引用assert_eq!(slice, &[2, 3]);