0


Rust 快速入门60分① 看完这篇就能写代码了

Rust 一门赋予每个人构建可靠且高效软件能力的语言https://hannyang.blog.csdn.net/article/details/130467813?spm=1001.2014.3001.5502关于Rust安装等内容请参考上文链接,写完上文就在考虑写点关于Rust的入门文章,本专辑将直接从Rust基础入门内容开始讲起。标题《快速入门60分》并不指60分钟,而是希望自己写完这个专辑后,可以得个60分,也能掌握Rust60%上下的内容,请看**第一章《变量与常量》:**

一、变量与常量

1.1 变量

1.1.1. 变量命名

变量名由字母、数字或下划线组成,应该具有描述性,能够清楚地表达变量的含义。命名的基本规则和大多数编程语言基本相同,有些细节上稍微有所不同。规则如下:

  1. 变量名必须以字母或下划线开头。
  2. 变量名不能以数字开头。
  3. 变量名区分大小写,推荐使用 snake_case 规则(字母全部小写和下划线)。
  4. 禁止使用和 Rust 关键字同名的变量名。
  5. 避免使用和 Rust 标准库中已有的函数、类型或模块同名的变量名。
  6. 对于私有变量 (private variables),可以使用 _ 作为前缀,区分开公共变量和私有变量。

1.1.2. 变量声明、赋值

Rust 变量声明使用 let 关键字,有些早期版本的basic语言也用LET(现在通常是DIM)

示例:

fn main() {
    let x = 323;
    let y = 3.23;
    print!("x: {}, ", x);
    println!("y: {}", y);
    //输出 x: 323, y: 3.23
}

上面示例中,**fn **是函数 function 的缩写,表示 main() 是这个rust程序的主函数;

let 变量名 = 常数;就是一个变量声明、赋值语句;

print!() 和 println!() 是打印的“宏”,宏不是函数,但功能也就相近于Java中的System.out.print()函数和System.out.println()函数的功能,两者输出差一个换行符。

// 表示注释语句,注释与C++相同,行注释用 //,块注释用 /* */;Rust另外还有文档注释。

函数体中每一行都是一个语句(当然语句也可以跨多行表达),语句由各种表达式组成。第一条语句必须有标点符号分号作结尾,表达式一般没有符号作结尾的。关于Rust中的“宏”,它和C/C++中的“宏”还是不同的,更多函数相关内容,放到之后的函数章节再讲。

let 语句也可以分成两行,先声明再分配值(赋值绑定):

fn main() {
    let x;
    x = 100;
    println!("x: {}", x); 
}

let 语句还可以一行赋值多个变量,但要加上括号(其实是复合数据类型之一的元组):

fn main() {
    let (x, y) = (3, 4);
    let z = (x*x+y*y) as f64;
    let z = z.sqrt().round() as i32;
    println!("{},{},{}", x, y, z); // 3,4,5
    let (a, b, c) = (1, 2, 3);
    println!("{},{},{}", a, b, c); // 1,2,3
}

其中,as 也是Rust关键字之一,在这里用于强制转换数据类型。

sqrt()、round() 分别为平方根、取整函数。

1.1.3. Snake case

Snake case 是一种命名规范,它使用小写字母,单词之间用下划线 "_" 连接。

Rust不推荐在变量中有大写字母,示例如下:

fn main() {
    let Int = 100;
    let My_Integer = 200;
    let my_integer = 300;
    
    println!("{} {} {}", Int, My_Integer, my_integer)
}

以上代码可以编译执行,但会有警告出现:

···Rust
warning: variable Int should have a snake case name
--> D:\Rust\hello.rs:2:9
|
2 | let Int = 100;
| ^^^ help: convert the identifier to snake case (notice the capitalization): int
|
= note: #[warn(non_snake_case)] on by default

warning: variable My_Integer should have a snake case name
--> D:\Rust\hello.rs:3:9
|
3 | let My_Integer = 200;
| ^^^^^^^^^^ help: convert the identifier to snake case: my_integer

warning: 2 warnings emitted

100 200 300
···

1.1.4. 禁止使用和避免使用

变量命名使用关键字,报错通不过编译,所以是禁止使用;但与标准库中已有的函数、类型同名,只是容易混淆,但编译不警告不报错,所以只能说是避免使用。如:

fn main() {
    //let fn = 10; //禁止使用
    //let let = 2; //禁止使用
    let u8 = 10u8; //避免使用
    let pow;       //避免使用
    pow = u8.pow(2);
    println!("{} {}", u8, pow)  //输出 10 100
}

其中,** u8 变量类型是8位无符号整型,pow**() 是标准库函数平方幂函数。

函数名、类型名称作变量名不会报错,而fn, let关键字作变量名则报错:

expected identifier, found keyword
   |
 help: escape `fn` to use it as an identifier 

1.1.5 匿名变量

下划线** _ *是一个特殊的变量名,更确切地说是变量名称的缺失,就称它为匿名变量。它的基本意思是舍弃,可以理解为废纸篓,这个变量扔掉不要了,不能被再次调用。(Go, Python里也有 _ 用作匿名变量,但细节各不相同,而且在python里 “_ = 5;print(_)” 是合法的*)

fn main() {
    let (a,_) = (6,2);
    println!("{}", a);
    //println!("{}", _); //报错^ `_` not allowed here
}

1.2 基本数据类型

1.2.1 整型

Rust整型 分为有符号整型(signed,标记 in)和无符号整型(unsigned,标记 un),区别在于数字是否有负数。带符号整型的安全存储范围为 -2^(n-1) 到 2^(n-1) - 1,无符号整型的安全存储范围为 0 到 2^n,n 为数据位长度,见下表:
位长度有符号无符号8-biti8u816-biti16u1632-biti32u3264-biti64u64128-biti128u128arch
由系统构架而定isizeusize
isize 和 usize 是根据系统架构决定的,例如带符号整型,如果系统是 64 位,类型为 i64,如果系统是 32 位,类型为 i32。(这和C++中的size_t类型相似

指定类型和默认类型

变量声明时,可以先指定类型,再分配绑定数值,变量名后面使用冒号跟随类型来明确指定变量的类型,称为显式指定;Rust 是强类型语言,具有自动判断变量类型的能力,可理解为这是隐式指定。以下示例中声明的变量 z 并没有明确指定其具体类型,则默认为 i32 类型,这也是 Rust 的特性之一类型推断

fn main() {
    let x: u8;
    x = 123;
    let y = -1000i64;
    let z = -323;  //不指定类型,默认为i32
    println!("x: {}, y: {}, z: {}", x, y, z);
}

1.2.2 浮点型

Rust浮点型 分为 32 位浮点数(f32)和 64 位浮点数(f64)。浮点型若不指定具体类型,则默认为 f64 浮点数,现在的高性能CPU对两种浮点数计算的速度几乎相同,但 64 位浮点数精度更高。

fn main() {
    let x: f32;
    x = 1.23;
    let y: f64 = 3.23;
    let z = -3.23;  //不指定类型,默认为f64
    println!("x: {}, y: {}, z: {}", x, y, z);
}

1.2.3 字符型

Rust字符型 是一个4字节 Unicode 码,支持中文等非英文字符,使用单引号''包括。

fn main() {
    let a = 'a';
    let b: char = '字';
    let c = '😊';
    println!("a: {}, b: {}, c: {}", a, b, c); 
}

1.2.4 布尔型

Rust布尔型 用 bool 表示,占用1个字节,值只能为 true 或 false,全小写非大写字母开头。(输出与声明同形,不像C/C++只能输出1和0

fn main() {
    let x = true;
    let y: bool = false;
    println!("x: {}, y: {}", x, y); //输出 x: true, y: false
}

1.3 变量的可变和不可变

1.3.1 不可变变量

先看一个实例:

fn main() {
    let x = 6;
    x = x + 1;  // 报错
    println!("{}", x)
}

在大多数编程语言中,上述实例应该打印出 7,但在Rust语言里却是报错:

 error[E0384]: cannot assign twice to immutable variable `x`
  --> D:\Rust\hello.rs:3:5
    |
 2 |     let x = 6;
    |         -
    |         |
    |         first assignment to `x`
    |         help: consider making this binding mutable: `mut x`
 3 |     x = x + 1;
    |     ^^^^^^^^^ cannot assign twice to immutable variable

意思就是: 不能为不可变变量x赋值两次,并提示考虑绑定可变:**mut** x

特别之处: Rust变量是不可变的!

通常来说变量将是可变的,但是在 Rust 中预设变量却是不可变的。Rust 鼓励使用不可变变量,当然如果明确知道该变量是可变得,就得用关键字 mut 附加说明它是可变的变量。

1.3.2 可变变量

可变变量要用 let mut 两个关键字来声明,示例如下:

fn main() {
    let mut x = 6;  // 可变变量声明要在let后附加mut关键字
    x = x + 1;
    println!("{}", x)  // 输出 7
}

1.3.3 变量遮蔽

Rust可以定义一个与之前变量同名的新变量,称之为第一个变量被第二个 Shadowing 了,官方用的这个词 Shadowing,有时被翻译成隐藏有时被翻译成遮蔽,还有的翻译为重影。它的意思就是当使用相同变量的名称时,编译器将“看到”第二个变量。实际上,第二个变量 “遮蔽” 了第一个变量,此时任何使用该变量名的行为中都会视为是在使用第二个变量,直到第二个变量自己也被隐藏或第二个变量的作用域结束。可以用相同变量名称来隐藏一个变量,以及重复使用 let 关键字来多次隐藏。总之,它和可变变量不是同一个概念。

fn main() {
    let x = 6;
    let x = x + 1;
    println!("{}", x);  // 7
    let x = x * x;
    println!("{}", x);  // 49
}

1.3.4 静态变量(全局变量)

静态变量用 static 声明的变量的生命周期是整个程序,从启动到退出。这也是Rust中唯一的声明全局变量的方法。它的生命周期永远是'static, 它占用的内存空间也不会在执行过程中回收。

注意点:

  1. 全局变量必须在声明的时候马上初始化;
  2. 命名时字母要全部大写,否则编译有警告信息;
  3. 全局变量的初始化必须是编译期就能确定的常量;
  4. 带有 **mut **修饰的全局变量,在使用的时候必须使用 unsafe 关键字;
  5. 全局变量可以写到函数外面,被任意一个函数使用。
fn main() {
    static G1 : i32 = 3;
    println!("{}, {}", G1, G1 + 20);

    static mut G2 : i32 = 4;
    unsafe {
        // G1 = 2; // cannot assign to immutable static item `G1`
        G2 = G1 + 5;
        println!("{}, {}", G1, G2);
    }
}

/* 输出
3, 23
3, 8
*/

1.4 常量

常量,和变量一样都是用来存储数据的标识符,常量使用 **

const

** 关键字声明。常量的值是不可变的,不允许使用mut关键字修饰这个变量绑定。

1.4.1 常量命名

常量的命名规则和方法与静态变量基本类似,命名时字母也要全部大写****。

错误示例:常量字母不全部大写可以通过编译,但有警告信息。

const pi:f32 = 3.14159; //报错
const Pi:f32 = 3.14159; //报错

fn main() {
    println!("{}", pi);
    println!("{}", Pi);
}
 warning: constant `pi` should have an upper case name
  --> D:\Cpp\hello.rs:1:7
    |
 1 | const pi:f32 = 3.14159;
    |       ^^ help: convert the identifier to upper case: `PI`
    |
   = note: `#[warn(non_upper_case_globals)]` on by default

warning: constant `Pi` should have an upper case name
  --> D:\Cpp\hello.rs:2:7
    |
 2 | const Pi:f32 = 3.14159;
    |       ^^ help: convert the identifier to upper case (notice the capitalization): `PI`

warning: 2 warnings emitted

3.14159
 3.14159

1.4.2 常量用法

常量必须显式指定类型以及声明同时就赋值,并且常量的值必须是编译时可确定的常数或者是常量表达式。示例如下:

const PI: f64 = 3.14159;
const FLAG: bool = true;
const HOURS: u32 = 12;
const SECONDS: u32 = 60 * 60 * HOURS;
const MIN_NUM: i32 = 1 << 31;
const MAX_NUM: i32 = -(1 + MIN_NUM);

fn main() {
    println!("{}", PI);
    println!("{}", FLAG);
    println!("{}", HOURS);
    println!("{}", SECONDS);
    println!("{}", MIN_NUM);
    println!("{}", MAX_NUM);
}

/* 输出:
3.14159
true
12
43200
-2147483648
2147483647
*/

错误示例:常量不可以隐式赋值,或者先声明后赋值。

const PI = 3.14159; //报错
const FLAG:bool;  //报错

fn main() {
    FLAG = true;  //报错
    println!("{}", PI);
    println!("{}", FLAG);
}
 error: free constant item without body
  --> D:\Cpp\hello.rs:2:1
    |
 2 | const FLAG:bool;
    | ^^^^^^^^^^^^^^^-
    |                |
    |                help: provide a definition for the constant: `= <expr>;`

error: missing type for `const` item
  --> D:\Cpp\hello.rs:1:9
    |
 1 | const PI = 3.14159;
    |         ^ help: provide a type for the constant: `: f64`

error[E0070]: invalid left-hand side of assignment
  --> D:\Cpp\hello.rs:5:10
    |
 5 |     FLAG = true;
    |     ---- ^
    |     |
    |     cannot assign to this expression

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0070`. 

1.4.3 标准库常量

引用标准库中的常量,使用关键字 use 来导入。(类似 java和python 中 import

比如std::f32或std::f64中的一些数学常量:

use std::f32::consts::PI;
use std::f32::consts::FRAC_1_PI;
use std::f32::consts::FRAC_2_PI;
use std::f32::consts::SQRT_2;
use std::f32::consts::FRAC_1_SQRT_2;
use std::f32::consts::E;
use std::f32::consts::LN_2;
use std::f32::consts::LOG2_E;
use std::f32::consts::LOG10_E;
fn main() {
    println!("{}", PI); 
    println!("{}", FRAC_1_PI);
    println!("{}", FRAC_2_PI);
    println!("{}", SQRT_2);
    println!("{}", FRAC_1_SQRT_2);
    println!("{}", E);
    println!("{}", LN_2);
    println!("{}", LOG2_E);
    println!("{}", LOG10_E);
}

/* 输出
3.1415927
0.31830987
0.63661975
1.4142135
0.70710677
2.7182817
0.6931472
1.442695
0.4342945
改std::f64,则输出
3.141592653589793
0.3183098861837907
0.6366197723675814
1.4142135623730951
0.7071067811865476
2.718281828459045
0.6931471805599453
1.4426950408889634
0.4342944819032518
*/

1.5 本章小结

  1. 变量(Variables):在 Rust 中,变量默认是不可变的(immutable),也就是说,一旦被赋值后,就不能再修改其值。如果需要修改变量的值,需要使用 mut 关键字来声明可变变量。

  2. 常量(Constants):与变量不同,常量在声明后就不能再修改其值。在 Rust 中,使用 const 关键字来声明常量,常量的命名规则与变量相同,但必须使用大写字母命名,并且必须在声明时就赋值。

  3. 可变绑定(Mutable bindings):除了使用 mut 关键字来声明可变变量外,还可以使用 let 关键字来声明一个可变绑定。可变绑定允许我们在不改变绑定本身的情况下修改绑定所指向的值。

  4. 类型推断(Type inference):Rust 支持类型推断,也就是说,可以在声明变量或常量时省略类型,由编译器自动推断类型。例如,可以使用 let x = 42; 来声明一个整数变量,编译器会自动推断出 x 的类型为 i32。

  5. 变量遮蔽(Variable shadowing):Rust 中可以使用相同的名称来声明一个新的变量或常量,这会遮蔽之前的变量或常量。这个特性可以用来在不改变原有代码的情况下修改变量的值或类型。

  6. 变量的作用域由声明的位置开始,直到当前作用域的结束;变量在离开作用域后会被自动销毁。常量在整个程序运行期间都存在。

注:本文中所有代码都可以在Rust官方线上编译器里编译通过。

Rust PlaygroundA browser interface to the Rust compiler to experiment with the languagehttps://play.rust-lang.org/?version=stable&mode=debug&edition=2021作者水平有限,如有不当之处,敬请指正。


本章完


本文转载自: https://blog.csdn.net/boysoft2002/article/details/130566884
版权归原作者 Hann Yang 所有, 如有侵权,请联系我们删除。

“Rust 快速入门60分① 看完这篇就能写代码了”的评论:

还没有评论