发布于10月24日10月24日 管理员 Rust基本语法变量和类型基本数据类型基本数据类型主要有整形、浮点、布尔以及字符类型。整形按照所占空间大小被分为1、2、4、8、16 字节大小的整数。每个大小又有有符号和无符号的差别。 具体的定义如下:LengthSignedUnsigned8-biti8u816-biti16u1632-biti32u3264-biti64u64128-biti128u128archisizeusize而浮点型包括f32和f64两个分别使用4字节和8字节的IEEE-754 浮点格式的浮点数。布尔类型和其他语言的布尔类型类似,用true和false来表示。字符类型是用''单引号括起来的字符。rust天生支持utf-8,所以任何单引号括起来的utf-8字符都是合法的字符类型变量。复合类型复合类型是基本类型和复合类型的组合,典型的有元组:Copylet tup: (i32, f64, u8) = (500, 6.4, 1);单纯的把几个类型放在一起。访问的时候通过下标索引来访问 比如 这里的500:tup.0数组:Copylet arr = [1, 2, 3, 4, 5];和元组不通的是,这里每个元素的类型必须是同样的。访问的时候,下标用中括号表示: arr[0]Copystruct: struct User { active: bool, username: String, email: String, sign_in_count: u64, } let user = User { email: String::from("someone@example.com"), username: String::from("someusername123"), active: true, sign_in_count: 1, };struct类似C语言里的struct,将多个类型组合在一起,通过成员名进行访问:user.email变量变量定义为:Copylet x = 5;这里x的类型是由系统推到而来的。也可以显示指定类型Copylet x:u32 = 5;这里x被赋值为5后,区别与其他语言的点。变量默认是不可以修改的,也就是:Copylet x = 5; x=6;会导致报错:Copyerror[E0384]: cannot assign twice to immutable variable `x` --> src/main.rs:4:5 | 2 | let x = 5; | - | | | first assignment to `x` | help: consider making this binding mutable: `mut x` 3 | println!("The value of x is: {x}"); 4 | x = 6; | ^^^^^ cannot assign twice to immutable variable但是可以用如下形式:Copylet x = 5; let x=6;甚至如下形式:Copylet x = 5; let x="6";这里,第二个let相当于重新定义一个变量,可以重新定义其类型。如果要修改变量,可以这样定义:Copylet mut x = 5; x=5;语句和表达式语句是指执行一段逻辑动作的代码,比如if语句,while语句。而表达式,是可以得到结果值的代码。比如1+1。 虽然表达式也可以执行逻辑,但是区别是表达式可以作为返回值,或者别的变量的赋值。而语句不行。let表达式let 主要用于变量的定义:Copylet condition = true;let还可以和if组合:Copylet number = if condition { 5 } else { "six" };这里if语句里面的值类似返回值。match表达式match可以做类型匹配和解包:Copylet config_max = Some(3u8); match config_max { Some(max) => println!("The maximum is configured to be {}", max), _ => (), }等同于上面的if let:Copylet config_max = Some(3u8); if let Some(max) = config_max { println!("The maximum is configured to be {}", max); }条件 语句if和Go语言的if比较类似,都是去除了传统语言里面的括号Copylet number = 3; if number < 5 { println!("only if"); } if number < 5 { println!("if else: condition was true"); } else { println!("if else: condition was false"); } if number < 5 { println!("if else if : number < 5 "); } else if number == 5 { println!("if else if : number == 5 "); } else{ println!("if else if : number > 5 "); }循环语句rust给无限循环增加了一个loop,约等于 while 1:Copyloop { println!("again and again!"); }但是loop可以通过break来返回一个结果:Copylet mut counter = 0; let result = loop { counter += 1; if counter == 10 { break counter * 2; } }; println!("The result is {result}");在循环中,可以通过类似goto的label定义,break到对应层级:Copylet mut count = 0; 'counting_up: loop { println!("count = {count}"); let mut remaining = 10; loop { println!("remaining = {remaining}"); if remaining == 9 { break; } if count == 2 { break 'counting_up; } remaining -= 1; } count += 1; } println!("End count = {count}");除了loop,常见的while也是有的:Copywhile true { println!("again and again!"); }以及for语句,不同于c-like语言,for语句是迭代器风格的,而不是两个";"三语句模式。Copylet a = [10, 20, 30, 40, 50]; for element in a { println!("the value is: {element}"); } // 模拟 int i=1; i<4; i++ for number in (1..4).rev() { println!("{number}!"); }函数函数分为main函数和普通函数。main函数是可执行程序的入口函数。对于库是不需要的。main函数本身也是个普通函数 只是函数名为main。Copyfn main() { println!("Hello, world!"); another_function(); } fn another_function() { println!("Another function."); }上面这个是不带参数,没有返回值的函数的最基本定义结构。首先用 fn开始,然后跟函数名以及()。最后用{},括起来 的函数逻辑.Copyfn main() { print_labeled_measurement(5, 'h'); } fn print_labeled_measurement(value: i32, unit_label: char) { println!("The measurement is: {value}{unit_label}"); }带参数的函数,在()中定义参数,参数为参数名:类型这样的格式。带返回的函数如:Copyfn main() { let x = plus_one(5); println!("The value of x is: {x}"); } fn plus_one(x: i32) -> i32 { x + 1 }在参数()和函数体{}中间用-> 分割,罗列返回值类型。这里体现了语句和表达式的区别。语句是执行一个动作,不具有可以作为直的结果。而表达式是可以作为值的结果的。 因此这里表达式x+1,作为值,直接进行范围。注意,此时后面不可以加;。struct和enumstruct定义结构体如下:Copystruct User { active: bool, username: String, email: String, sign_in_count: u64, }结构为struct关键字加上大写开头的类型名,后面跟{}包裹的成员变量,每个成员变量为成员名:类型,。struct的初始化:Copylet user1 = User { email: String::from("someone@example.com"), username: String::from("someusername123"), active: true, sign_in_count: 1, };如果用其他struct来初始化同类型时,可以用:Copylet user2 = User { email: String::from("another@example.com"), ..user1 };有一种特殊的struct,元组struct:Copystruct Color(i32, i32, i32); struct Point(i32, i32, i32); fn main() { let black = Color(0, 0, 0); let origin = Point(0, 0, 0); println!("black 0:{}", black.0) }还有种更特殊的struct:Copystruct AlwaysEqual; fn main() { let subject = AlwaysEqual; }他的值可以是{},所以在代码中看到{}就可以认为是一个不占空间的struct的值,比如:CopyOk({})enumrust中的enum比任何其他语言的都强大。简单版本:Copyenum IpAddrKind { V4, V6, }这个容易理解,使用的时候就是 let four = IpAddrKind::V4;。指定类型版本:Copyenum IpAddr { V4(String), V6(String), }使用的时候:let home = IpAddr::V4(String::from("127.0.0.1")); 这就有点不像传统enum了。更像一个struct定义。 这里"V4","V6"同样的类型,还不直观。Copystruct Ipv4Addr { // --snip-- } struct Ipv6Addr { // --snip-- } enum IpAddr { V4(Ipv4Addr), V6(Ipv6Addr), }V4是一个类型,V6是一个类型。这个时候enum更像union。也还好理解。来个不容易看的:Copyenum IpAddr { V4(u8, u8, u8, u8), V6(String), } let home = IpAddr::V4(127, 0, 0, 1);这里V4变成了一个元组类型。虽然可读性差一点,但是写法方便。最复杂的:Copyenum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32), }Message定义了一个游戏的消息指令,这里在传统语言如C++中,可能要定义个Message基类,然后每个命令消息再去定义子类。而这里一个enum搞定。这个时候,这个enum真不好说他是什么功能。给struct/enum定义方法给struct定义方法:Copy#[derive(Debug)] struct Rectangle { width: u32, height: u32, } impl Rectangle { fn area(&self) -> u32 { self.width * self.height } } fn main() { let rect1 = Rectangle { width: 30, height: 50, }; println!( "The area of the rectangle is {} square pixels.", rect1.area() ); }使用impl Xxx {} 语法,在{}的方法,就是成员方法。其中不带(&self)参数的是类方法,第一个参数为(&self)的为类方法。这个类似python2。给enum定义也是一样,用impl Xxx {}Copyimpl Message { fn call(&self) { // method body would be defined here } } let m = Message::Write(String::from("hello")); m.call();枚举的强大还体现在他的使用上,再不需要上面的类继承来做反射:Copypub enum NameRegistryInstruction { Create { hashed_name: Vec<u8>, lamports: u64, space: u32, }, Update { offset: u32, data: Vec<u8> }, Transfer { new_owner: Pubkey }, Delete, Realloc { space: u32, }, } match instruction { NameRegistryInstruction::Create { hashed_name, lamports, space, } => { msg!("Instruction: Create"); Processor::process_create(program_id, accounts, hashed_name, lamports, space)?; } NameRegistryInstruction::Update { offset, data } => { msg!("Instruction: Update Data"); Processor::process_update(accounts, offset, data)?; } NameRegistryInstruction::Transfer { new_owner } => { msg!("Instruction: Transfer Ownership"); Processor::process_transfer(accounts, new_owner)?; } NameRegistryInstruction::Delete => { msg!("Instruction: Delete Name"); Processor::process_delete(accounts)?; } NameRegistryInstruction::Realloc { space } => { msg!("Instruction: Realloc Name Record"); Processor::process_realloc(accounts, space)?; } }通过match语句,首先能对enum做类型匹配,匹配的同时,还可以对类型做解包, 如NameRegistryInstruction::CreateCopy{ hashed_name, lamports, space, }这里其实是一个没有给名字的struct。容器list/vectorCopyVec<T>vec是std提供的链表类型。可以用来存放相同类型的数组。创建指定类型的vector:Copylet v: Vec<i32> = Vec::new();也可以通过vec!宏直接赋值初始化:Copylet v = vec![1, 2, 3];增加元素:Copylet mut v = Vec::new(); v.push(5); v.push(6); v.push(7); v.push(8);这里mut表示vector是可以做增删修改的。通过remove进行删除元素:Copylet mut v = vec![1, 2, 3]; assert_eq!(v.remove(1), 2); assert_eq!(v, [1, 3]);可以通过get给定下标,获取vector的元素,通过Option来做判断是否存在:Copylet v = vec![1, 2, 3, 4, 5]; let third: &i32 = &v[2]; println!("The third element is {third}"); let third: Option<&i32> = v.get(2); match third { Some(third) => println!("The third element is {third}"), None => println!("There is no third element."), }通过迭代器,遍历:Copylet v = vec![100, 32, 57]; for n_ref in &v { // n_ref has type &i32 let n_plus_one: i32 = *n_ref + 1; println!("{n_plus_one}"); }上面这个是只读的,如果需要修改,使用:Copylet mut v = vec![100, 32, 57]; for n_ref in &mut v { // n_ref has type &mut i32 *n_ref += 50; }Stringrust的String不是基础类型,是由std提供的类型。创建字符串可以用:Copylet mut s = String::new(); let data = "initial contents"; let s = data.to_string(); let s = String::from("initial contents");三种方法。修改字符串:Copylet mut s = String::from("foo"); s.push_str("bar"); let mut s1 = String::from("foo"); let s2 = "bar"; s1.push_str(s2); println!("s2 is {s2}"); let mut s = String::from("lo"); s.push('l'); let s1 = String::from("Hello, "); let s2 = String::from("world!"); let s3 = s1 + &s2; // note s1 has been moved here and can no longer be used可以使用push_str、push甚至是"+"来修改字符串。注意"+"会borrow变量。当然要修改字符串前提是字符串是"mut"的。可以通过下标操作。或者字符串中的字符:Copylet s1 = String::from("hello"); let h = s1[0];Maprust中的map也不是基础类型,而是std提供的,并且也和一般语言中不一样,类似Java里面明确的命名为"HashMap"创建:Copyuse std::collections::HashMap; let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.insert(String::from("Yellow"), 50);访问:Copyuse std::collections::HashMap; let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.insert(String::from("Yellow"), 50); let team_name = String::from("Blue"); let score = scores.get(&team_name).copied().unwrap_or(0);遍历:Copyuse std::collections::HashMap; let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.insert(String::from("Yellow"), 50); for (key, value) in &scores { println!("{key}: {value}"); }插入修改:Copyuse std::collections::HashMap; let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.insert(String::from("Blue"), 25); println!("{:?}", scores);判断是否存在,存在才插入:Copyuse std::collections::HashMap; let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.entry(String::from("Yellow")).or_insert(50); scores.entry(String::from("Blue")).or_insert(50); println!("{:?}", scores);traittrait 类似其他语言中的接口,但是就好比enum一样,他不仅类似其他语言的接口,他更强大。 更复杂。很多继承的特性都是通过 trait 来实现。trait 的定义类似struct:Copypub trait Summary { fn summarize(&self) -> String; }trait主要是定义方法。这里方法就是个普通的函数定义。但是去掉了参数名。trait只是定义了接口方法,而具体实现需要再struct中实现:Copypub struct NewsArticle { pub headline: String, pub location: String, pub author: String, pub content: String, } impl Summary for NewsArticle { fn summarize(&self) -> String { format!("{}, by {} ({})", self.headline, self.author, self.location) } } pub struct Tweet { pub username: String, pub content: String, pub reply: bool, pub retweet: bool, } impl Summary for Tweet { fn summarize(&self) -> String { format!("{}: {}", self.username, self.content) } }使用impl关键字,跟要实现的trait名加上"for Xxx"给具体的struct视线。这里还可以再trait中给出默认实现:Copypub trait Summary { fn summarize(&self) -> String { String::from("(Read more...)") } }这样,在"impl"里面没有"summarize"方法实现时,就默认用trait里面的定义。trait的作用主要要结合泛型限制,和参数专递才能体现。比如类似其他语言中基本的OOP的动态:Copypub fn notify(item: &impl Summary) { println!("Breaking news! {}", item.summarize()); }这里将参数声明为trait,任何实现了这个traint的类型都可以传递进来。具体的summarize是 传入进来的类型的实现。除了可以限制参数,还可以限制返回值。这个就有点类似其他语言的基类、接口。Copyfn returns_summarizable() -> impl Summary { Tweet { username: String::from("horse_ebooks"), content: String::from( "of course, as you probably already know, people", ), reply: false, retweet: false, } }和泛型的结合,见下一章。泛型泛型是rust最强的地方,也是rust最难的地方,更是学习rust的拦路虎。来看个定义:Copypub struct Iter<'a, K, V> { db_iter: rocksdb::DBIterator<'a>, _phantom: PhantomData<(K, V)>, } impl<'a, K: DeserializeOwned, V: DeserializeOwned> Iter<'a, K, V> { pub(super) fn new(db_iter: rocksdb::DBIterator<'a>) -> Self { Self { db_iter, _phantom: PhantomData, } } } impl<'a, K: DeserializeOwned, V: DeserializeOwned> Iterator for Iter<'a, K, V> { type Item = (K, V); fn next(&mut self) -> Option<Self::Item> { let (key, value) = self.db_iter.next()?; let key = bincode::deserialize(&key[PREFIX_LEN..]).ok()?; let value = bincode::deserialize(&value).ok()?; Some((key, value)) } }感觉正常人都看不懂这个是什么。回到泛型基础语法上来。先来看定义函数:Copyfn largest<T>(list: &[T]) -> &T { let mut largest = &list[0]; for item in list { if item > largest { largest = item; } } largest } fn main() { let number_list = vec![34, 50, 25, 100, 65]; let result = largest(&number_list); println!("The largest number is {}", result); let char_list = vec!['y', 'm', 'a', 'q']; let result = largest(&char_list); println!("The largest char is {}", result); }这里定义的largest函数,后面接了"<T>"这个还算正常,学过C++都知道这里是一个模板定义,或者说类型定义。后续T 代表着一种类型。还可以出现在结构体中:Copystruct Point<T> { x: T, y: T, } impl<T> Point<T> { fn x(&self) -> &T { &self.x } } fn main() { let p = Point { x: 5, y: 10 }; println!("p.x = {}", p.x()); }这里"impl"也要加上"<T>"以及枚举中,如典型的Result:Copyenum Result<T, E> { Ok(T), Err(E), }在后面有介绍生命周期,生命周期也类似类型,也需要放在这里'<>' 如:Copypub struct Iter<'a, K, V> { db_iter: rocksdb::DBIterator<'a>, _phantom: PhantomData<(K, V)>, }
创建帐户或登录后发表意见