rust 初探 -- 通用编程概念

rust 初探 – 通用编程概念

变量和可变性

  • 声明变量使用 let 关键值
  • 默认情况下,变量是不可变的(immutable),可以在变量前面加上 mut,就可以使变量可变

变量和常量

  • 常量(constant):常量在绑定值之后是不可变的,但是它和不可变的变量不同:
    • 不可以使用 mut,常量永远都是不可变的
    • 声明常量使用 const 关键字,它的类型必须被标注
    • 常量可以在任何作用域内进行声明,包括全局作用域
    • 常量只能绑定到常量表达式,无法绑定到函数的调用结果或只能在运行时才能计算出的值
  • 在程序运行期间,常量在其声明的作用域里一直有效
  • 命名规范:rust 常量使用全大写字母,每个单词之间用下划线分开:
    const MAX_POINT:u32 = 100

Shadowing

  • 可以使用相同的名字声明新的变量,新的变量就会 shadow 之前声明的同名变量
    • 在后续的代码汇总这个变量名代表的就是新的变量
fn main() {
	let x = 5;
	let x = x + 1;
	println!("x is {}", x); // x is 6
}

运行结果:

hope@hopedeMacBook-Air hello_cargo % cargo run     
   Compiling hello_cargo v0.1.0 (/Users/hope/rust/hello_cargo)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.41s
     Running `target/debug/hello_cargo`
x is 6
  • shadow 和把变量标记为 mut 是不一样的:
    • 如果不使用 let 关键字,那么重新给非 mut 的变量赋值就会导致编译时错误
    • 而使用 let 声明的同名新变量,也是不可变的
    • 使用 let 声明的同名新变量,它的类型可以与之前不同
fn main() {
    let x = "string";
    let x = x.len();
    println!("x is {}", x);
}

运行结果:

hope@hopedeMacBook-Air hello_cargo % cargo run
   Compiling hello_cargo v0.1.0 (/Users/hope/rust/hello_cargo)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.29s
     Running `target/debug/hello_cargo`
x is 6

数据类型:标量类型

一个标量类型代表一个单个的值

  • rust 是静态编译语言,在编译时必须知道所有变量的类型
    • 基于使用的值,编译器通常能够推断出它的具体类型
    • 但如果可能的类型比较多,就必须添加类型的标注,否则编译会报错
fn main() {
    let guess = "42".parse().expect("not a number");
    // let guess :i32 = "42".parse().expect("not a number"); // 正确的写法
    println!("guess is {}", guess);
}
   Compiling hello_cargo v0.1.0 (/Users/hope/rust/hello_cargo)
error[E0284]: type annotations needed
 --> src/main.rs:2:9
  |
2 |     let guess = "42".parse().expect("not a number");
  |         ^^^^^        ----- type must be known at this point
  |
  = note: cannot satisfy `<_ as FromStr>::Err == _`
help: consider giving `guess` an explicit type
  |
2 |     let guess: /* Type */ = "42".parse().expect("not a number");
  |              ++++++++++++

For more information about this error, try `rustc --explain E0284`.
error: could not compile `hello_cargo` (bin "hello_cargo") due to 1 previous error
整数类型

在这里插入图片描述

  • 有符号范围:-2n-1 ~ (2n-1-1)
  • 无符号范围:0 ~ (2n-1)
  • arch:代表系统架构,32位或者64位
整数字面量
  • 除了 byte 类型外,所有数值字面值都允许使用类型后缀(如:57u8)
  • 整数的默认类型就是 i32
整数溢出
  • 调试模式下编译:会检查整数溢出,如果发生溢出,会在运行时panic
  • 发布模式下不会检查可能导致 panic 的整数溢出,会执行“环绕” 操作(u8 的256 变成 0)
浮点类型
  • f32,32位,单精度
  • f64,64位,双精度
  • f64 是默认类型,因为在现代 CPU 上 f64 和 f32 速度差不多,而且精度更高
布尔类型
  • 有两个值:true ,false
  • 一个字节大小,符号是 bool
字符类型
  • char 类型被用来描述语言中最基础的单个字符
  • 字符类型的字面值使用单引号
  • 占用 4 字节大小
  • 是 unicode 标量值,可以表示比 ASCII 多得多的字符内容
  • 但是 unicode 中并没有“字符”的概念,所以直觉上认为的字符也许与 rust 中的概念并不相符

数据类型:复合类型

复合类型可以将多个值放到一个类型里面,rust 中提供了两种基础的复合类型:元组(Tuple),数组

Tuple
  • Tuple 可以将多个类型的多个值放到一个类型里
  • Tuple 的长度是固定的:一旦声明就无法改变
  • 创建 Tuple:在小括号里,将值用逗号分开
  • Tuple 中的每个位置都对应一个类型,Tuple 中各元素的类型不必相同
fn main() {
   let tup:(i32, f64, u8) = (500, 6.7, 1);
   println!("{}, {}, {}", tup.0, tup.1, tup.2); // 使用点标记法,获取
}

可以使用模式匹配来解构一个 Tuple 来获取元素的值

fn main() {
   let tup:(i32, f64, u8) = (500, 6.7, 1);
   let (x, y, z) = tup;
   println!("{}, {}, {}", x, y, z);
}
数组
  • 数组也可以多个值放在一个类型里
  • 数组中的每个元素的类型必须相同
  • 数组的长度也是固定的
  • 声明:在中括号里,使用逗号分开
数组的用处
  • 想让数据存放在 stack 上而不是 heap 上,或者想保证有固定数量的元素,使用数组更有好处
  • 数组没有 Vector 灵活,Vector 和数组类似,由标准库提供
  • Vector 的长度是可以改变的
数组的类型
  • 例如:let a:[i32;5] = [1,2,3,4,5];
  • 例如:let a:[1;5];相当于let a:[i32;5] = [1,1,1,1,1];
数组的访问

使用索引访问即可,如果访问的索引超过了数组的范围,编译不会通过,运行也会报错

函数

  • 声明函数使用 fn 关键字
  • 针对函数和变量名,rust 使用 snake case 命名规范:所有字母都小写,单词之间使用下划线分开
函数的参数
  • 函数中定义的 parameters,调用时传入的 arguments
  • 函数签名里,必须声明函数的类型,多个参数必须单独声明
函数体中的语句与表达式
  • 函数体由一系列语句组成,可选的由一个表达式结束
  • rust 是一个基于表达式的语言
  • 语句是执行一些动作的指令
  • 表达式会计算产生一个值
  • 函数的定义也是语句
  • 语句不返回值,所以不可以使用let 将一个语句赋给一个变量
fn main() {
    let x = 5;
    let y = {
        let x = 1;
        x + 3 // 这时候是 4
    };

    // let y = {
    //     let x = 1;
    //     x + 3; // 语句,这时候是一个空的 ()
    // };

    println!("{}", y);
}
函数的返回值
  • 在 -> 符号后面声明函数返回值的类型,但是不可以为返回值命名
  • 在 rust 里吗,返回值就是函数体里吗最后一个表达式的值
  • 若想提前返回,需使用 return 关键字,并指定一个值(默认使用最后一个表达式作为返回值)
fn main() {
    let x = add(1);

    println!("{}", x); // 2
}

fn add(x: i32) -> i32 {
    x + 1
}

控制流:if else

if 表达式
  • 和 go 一样,但是如果使用了多个 else if,建议使用 match 来重构代码

控制流:循环

loop
  • 一直执行,直到主动停止
while
  • 每次执行,都需要判断一次条件
for
  • 一般用来遍历
fn main() {
    let a = [1, 2, 3, 4];
    for v in a.iter() {
    	println!("{}", v); // 1 2 3 4
    }
}

fn main() {
    // let a = [1, 2, 3, 4];
    // for v in a.iter() {
    // 	println!("{}", v);
    // }
    for v in (1..4).rev() {
    	println!("{}", v); // 反转 3 2 1
    }
}
  • 21
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jiangw557

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值