rust cargo

cargo创建项目编辑打包

 
创建lib项目 
cargo new --lib my_lib

cargo是rust的编译与打包工具,可将rust打包成为一个可执行性文件。
生成的可执行性文件不能跨系统的大版本,比如在linux7上打包,那么程序无法在linux6上执行。

# cargo new hello_cargo
Created binary (application) `hello_cargo` package
# cd hello_cargo
# ls
Cargo.toml src

# cat Cargo.toml 
[package]
name = "hello_cargo"
version = "0.1.0"
authors = ["tanpf itoracle@163.com"]
edition = "2018"

[dependencies]

cargo build

 
# cd src
# ls
main.rs
# cat main.rs 
fn main() {
    println!("Hello, world!");
}

[root@itoracle src]# cargo build
   Compiling hello_cargo v0.1.0 (/usr/local/automng/src/rust/test/hello_cargo)                                                                                              
    Finished dev [unoptimized + debuginfo] target(s) in 3.05s                                                                                                               
[root@itoracle src]# ll
total 4
-rw-r--r-- 1 root root 45 Jan 15 18:16 main.rs

[root@itoracle hello_cargo]# ./target/debug/hello_cargo 
Hello, world!

cargo run

 
[root@itoracle hello_cargo]# cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.01s                                                                                                               
    Running `target/debug/hello_cargo`
Hello, world!

[root@itoracle hello_cargo]# vim src/main.rs 

fn main() {
    println!("Hello, world!");
    println!("过年回家的火车票,为啥每次都抢不到呢");
}
如果修改了代码,cargo run会先编译再运行


[root@itoracle hello_cargo]# cargo run
   Compiling hello_cargo v0.1.0 (/usr/local/automng/src/rust/test/hello_cargo)                                                                                              
    Finished dev [unoptimized + debuginfo] target(s) in 0.46s                                                                                                               
     Running `target/debug/hello_cargo`
Hello, world!
过年回家的火车票,为啥每次都抢不到呢

cargo check

 
cargo check进行代码的编译,但不生成可执行文件,速度比cargo build快很多,当代码比较多时,可以先check
[root@itoracle hello_cargo]# cargo check
    Checking hello_cargo v0.1.0 (/usr/local/automng/src/rust/test/hello_cargo)                                                                                              
    Finished dev [unoptimized + debuginfo] target(s) in 0.13s 

rust 标识符

标识符

 
The first character is a letter.
The remaining characters are alphanumeric or _.
或
The first character is _.
The identifier is more than one character. _ alone is not an identifier.
The remaining characters are alphanumeric or _.

Raw identifiers

 
如果想使用Rust的关键字作为标识符,则需要以r#为前缀
Sometimes, you may need to use a name that’s a keyword for another purpose. 
Maybe you need to call a function named match that is coming from a C library, 
where ‘match’ is not a keyword. 
To do this, you can use a “raw identifier.” Raw identifiers start with r#:

 
let r#fn = "this variable is named 'fn' even though that's a keyword";

// call a function named 'match'
r#match();

rust variables and mutability

mutability

 
rust中的变量默认不能修改,想修改得加上mut
cargo new variables
[root@itoracle test]# vim variables/src/main.rs 
fn main() {
    let x = 5;
    println!("The value of x is: {}", x);
    x = 6;
    println!("The value of x is: {}", x);
}

以上代码将在 编译时 报错

 
rust默认变量是不能对其值修改的。以下代码是正确的
fn main() {
    let mut x = 5;
    println!("The value of x is: {}", x);
    x = 6;
    println!("The value of x is: {}", x);
}

[root@itoracle test]# cd variables/ 
[root@itoracle variables]# cargo run
   Compiling variables v0.1.0 (/usr/local/automng/src/rust/test/variables)                                               
    Finished dev [unoptimized + debuginfo] target(s) in 3.15s                                                            
     Running `target/debug/variables`
The value of x is: 5
The value of x is: 6

rust 常量

变量与常量

 
区别:
常量必须在编辑时就确定其值,
变量可以是表达式,可以在运行时确定其值。
First, you aren’t allowed to use mut with constants. 
Constants aren’t just immutable by default—they’re always immutable.

You declare constants using the const keyword instead of the let keyword, 
and the type of the value must be annotated. 
Just know that you must always annotate the type.

Constants can be declared in any scope, including the global scope, 
which makes them useful for values that many parts of code need to know about.

The last difference is that constants may be set only to a constant expression, 
not the result of a function call or any other value that could only be computed at runtime.

Here’s an example of a constant declaration 
where the constant’s name is MAX_POINTS and its value is set to 100,000. 
(Rust’s naming convention for constants is to use all uppercase with underscores between words, 
and underscores can be inserted in numeric literals to improve readability):

const在命名时就必须赋值

 
[root@itoracle variables]# vim src/main.rs 
fn main() {
    let mut x = 5;
    println!("The value of x is: {}", x);
    x = 6;
    println!("The value of x is: {}", x);

    const MAX_POINTS: u32 = 100_000;
    println!("常量:{}",MAX_POINTS)
}

rust 注释

单行注释

 
All programmers strive to make their code easy to understand, 
but sometimes extra explanation is warranted. 
In these cases, programmers leave notes, or comments, 
in their source code that the compiler will ignore but people reading the source code may find useful.

//单行注释
fn main() {
    let lucky_number = 7; // I’m feeling lucky today
}

fn main() {
    // I’m feeling lucky today
    let lucky_number = 7;
}

rust 流程控制

rust if 条件表达式

 
fn main() {
    let number = 6;

    if number % 4 == 0 {
        println!("number is divisible by 4");
    } else if number % 3 == 0 {
        println!("number is divisible by 3");
    } else if number % 2 == 0 {
        println!("number is divisible by 2");
    } else {
        println!("number is not divisible by 4, 3, or 2");
    }
}
if后面的条件不加中括号

if 中使用 let 语句

 
要求 if 条件各个分支返回的数据类型必须相同

fn main() {
    let condition = true;
    let number = if condition {
        5
    } else {
        6
    };

    println!("The value of number is: {}", number);
}

rust loop循环

无返回值

 
fn main() {
    let mut count = 1;
    loop{
        count += 1;
        if count == 8{
            break;
        }
    }
}

有返回值

 
fn main() {
    let mut counter = 0;
    
        let result = loop {
            counter += 1;
    
            if counter == 10 {
                break counter * 2;
            }
        };
        //assert_eq!方法可以在result的值不为20时抛出异常
        assert_eq!(result, 20);
    }

比如上面的方法,如果写成 assert_eq!(result, 19); 
则在运行时会给出以下错误信息
[root@itoracle functions]# cargo run
   Compiling functions v0.1.0 (/usr/local/automng/src/rust/test/functions)                                                                                                  
    Finished dev [unoptimized + debuginfo] target(s) in 1.80s                                                                                                               
     Running `target/debug/functions`
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `20`,
 right: `19`', src/main.rs:12:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

rust 简单类型

Rust has four primary scalar types: integers, floating-point numbers, Booleans, and characters

整数类型

 
u32,this type declaration indicates that the value 
it’s associated with should be an unsigned integer (signed integer types start with i, instead of u) 
that takes up 32 bits of space. 

Additionally, the isize and usize types depend on the kind of computer your program is running on: 
64 bits if you’re on a 64-bit architecture and 32 bits if you’re on a 32-bit architecture.

 
Note that all number literals except the byte literal allow a type suffix, 
such as 57u8, and _ as a visual separator, such as 1_000.

整数溢出

 
Let’s say that you have a u8, 
which can hold values between zero and 255. 

What happens if you try to change it to 256? 
This is called “integer overflow,” and 
Rust has some interesting rules around this behavior. 

When compiling in debug mode, 
Rust checks for this kind of issue and will cause your program to panic, 
which is the term Rust uses when a program exits with an error. 

In release builds, Rust does not check for overflow, 
and instead will do something called “two’s complement wrapping.” 

In short, 256 becomes 0, 257 becomes 1, etc. 
Relying on overflow is considered an error, even if this behavior happens. 
If you want this behavior explicitly, 
the standard library has a type, Wrapping, that provides it explicitly.

浮点类型

 
Rust’s floating-point types are f32 and f64, which are 32 bits and 64 bits in size, respectively. 
The default type is f64 because on modern CPUs 
it’s roughly the same speed as f32 but is capable of more precision.

 
fn main() {
    let x = 64.0 ; //f64
    let y: f32 = 32.0; //f32
    println!("64:{},32:{}",x,y);
}

 
The f32 type is a single-precision float, and f64 has double precision.

数字运算

 
fn main() {
    // addition
    let _sum = 5 + 10;

    // subtraction
    let _difference = 95.5 - 4.3;

    // multiplication
    let _product = 4 * 30;

    // division
    let _quotient = 56.7 / 32.2; //1.7608695652173911 小数点后16位
    let _ff32 = 7f32 / 3f32;   //2.3333333  7位小数

    // remainder
    let _remainder = 13 % 5;  //3
    println!{"32位除法:{}",_ff32}
    println!{"默认64位除法:{}",_quotient};
    println!{"求余:{}",_remainder};
}

 
整数与浮点数不可以混合运算,比如 let _cc = 10 * 3.0; 会报以下错误

^ no implementation for `{integer} * {float}`

error: Could not compile `datatype`.

布尔类型

 
fn main() {
    let _t = true;
    let _f: bool = false; // with explicit type annotation
}

字符类型

 
fn main() {
    let _a = 'z';
    let _b = 'ℤ';
    let _c = 'Z';
}

 
Rust’s char type represents a Unicode Scalar Value, which means it can represent a lot more than just ASCII. 
Accented letters; Chinese, Japanese, and Korean characters; emoji; 
and zero-width spaces are all valid char values in Rust. 
Unicode Scalar Values range from U+0000 to U+D7FF and U+E000 to U+10FFFF inclusive. 
However, a “character” isn’t really a concept in Unicode, 
so your human intuition for what a “character” is may not match up with what a char is in Rust.

rust 复合类型

tuples and arrays

 
Compound types can group multiple values into one type. 
Rust has two primitive compound types: 
tuples and arrays.

元组存放数据的数据类型可以不同,数组则必须是相同类型。

rust元组:定长

 
A tuple is a general way of grouping together some number of other values with a variety of types into one compound type. 
Tuples have a fixed length: once declared, they cannot grow or shrink in size.

Each position in the tuple has a type, and the types of the different values in the tuple don’t have to be the same. 

 
fn main() {
    let _tup: (i32, f64, u8) = (500, 6.4, 1);
    let _aa = (1,2.3,"wa ka ka ");
    let (_x,_y,_z) = _aa;
    println!("The value of z is:{}",_z)
}

 
This program first creates a tuple and binds it to the variable tup. 
It then uses a pattern with let to take tup and turn it into three separate variables, x, y, and z. 
This is called destructuring, because it breaks the single tuple into three parts. 

In addition to destructuring through pattern matching, 
we can access a tuple element directly by using a period (.) followed by the index of the value we want to access. 

 
fn main() {
    let _x: (i32, f64, u8) = (500, 6.4, 1);
    let _five_hundred = _x.0;
    let _six_point_four =_x.1;
    let _one = _x.2;
    println!("第三个元素:{}",_one);
}

rust数组:定长,中括号

 
Unlike a tuple, every element of an array must have the same type. 
Arrays in Rust are different from arrays in some other languages 
because arrays in Rust have a fixed length, like tuples.

C/C++中的数组也是定长,且数组用的是花括号 ,int a[]={1,2,3};
python不是定长,用的是中括号[],
个人也支持rust使用中括号,因为花括号在大多语言中表示的是字典,中括号[]表示的则是列表

 
fn main() {
    let _a = [1, 2, 3, 4, 5];
}

 
Arrays are useful when you want your data allocated on the stack rather than the heap or 
when you want to ensure you always have a fixed number of elements.
 An array isn’t as flexible as the vector type, though. 
 A vector is a similar collection type provided by the standard library that is allowed to grow or shrink in size. If you’re unsure whether to use an array or a vector, you should probably use a vector. 

It’s very unlikely that such a program will need to add or remove months, 
so you can use an array because you know it will always contain 12 items

 
fn main() {
    let _a = [1, 2, 3, 4, 5];
    let _months = ["January", "February", "March", "April", "May", "June", "July",
                "August", "September", "October", "November", "December"];
}

 
Arrays have an interesting type; it looks like this: [type; number]. For example:

 
fn main() {
    let _b: [i32; 5] = [1, 2, 3, 4, 5];
}

rust 数组

访问数组元素

 
fn main() {
    let _b: [i32; 5] = [1, 2, 3, 4, 5];
    let _c1 = _b[0];
    let _c2 = _b[1];
}

数组越界

 
fn main() {
    let a = [1, 2, 3, 4, 5];
    let index = 10;

    let element = a[index];

    println!("The value of element is: {}", element);
}

编译阶段不会报错,在运行时会报错

 
[root@itoracle src]# cargo build
    Compiling datatype v0.1.0 (/usr/local/automng/src/rust/test/datatype)                                                 
     Finished dev [unoptimized + debuginfo] target(s) in 1.39s                                                            
 [root@itoracle src]# cargo run
     Finished dev [unoptimized + debuginfo] target(s) in 0.01s                                                            
      Running `/usr/local/automng/src/rust/test/datatype/target/debug/datatype`
 thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 10', src/main.rs:5:19
 note: Run with `RUST_BACKTRACE=1` for a backtrace.

数据遍历

 
pub fn test_for(){
    let aa = [1,2,3,4,5];
    let mut index = 0;
    for bb in aa.iter() {
        println!("{}:{}",index,bb);
        index = index +1;
    }
}

pub fn test_for2(){
    let aa = [1,2,3,4,5];
    for (index,&bb) in aa.iter().enumerate() {
        println!("{}:{}",index,bb);
    }
}

初始化指定长度数组

 
pub fn test() {

    let buffer = [0; 1024];
    for (idx, &val) in buffer.iter().enumerate(){
        println!("{}:{}",idx,val);
    }
}

 
......
......
......
1015:0
1016:0
1017:0
1018:0
1019:0
1020:0
1021:0
1022:0
1023:0

rust 格式化输出

简单类型

 
fn main() {
    let a = 1;
    let b = 'b';
    let c = 1.2;
    let d = true;
    println!("a={},b={},c={},d={}",a,b,c,d);//a=1,b=b,c=1.2,d=true
}

format的使用

 
不做任何类型格式化原样输出
format!("{}", foo) -> "3735928559"

以十六进制数的形式输出
format!("0x{:X}", foo) -> "0xDEADBEEF"

以八进制的形式输出
format!("0o{:o}", foo) -> "0o33653337357"

数字转指定长度字符串,不足时补0

 
pub fn num2str_pad0(num:usize, max_len:usize) -> String {
    let l1 = max_len;
    let s2 = format!("{}",num);
    let l2 = s2.len();

    if l1 <= l2 {
        s2
    }else {
        let l3 = l1 - l2 -1;
        let mut s3 = String::from("0");

        for i in 0..l3 {
            s3 += "0";
        }

        s3 += &s2;
        s3
    }
}

pub fn num2str_pad0_test(){
    let num = 123;
    let ss = num2str_pad0(num as usize,5);
    println!("pad 0:{}",ss);  //pad 0:00123

}

rust 类型转换

显式类型转换

 
fn data02(){
    println!("-------显式类型转换-------");
    let a = 1;
    let b = a as f64;
    let c = b * 2.0;
    println!("c={}",c);  //c=2
    println!("-------------------------------------------------------");
}

 
let guess: u32 = "42".parse().expect("Not a number!");

rust 函数

 
[root@itoracle src]# cargo new functions
    Created binary (application) `functions` package
[root@itoracle src]# cd functions/
[root@itoracle functions]# vim src/main.rs

 
Rust code uses snake case as the conventional style for function and variable names. 
In snake case, all letters are lowercase and underscores separate words. 
Here’s a program that contains an example function definition:

Rust doesn’t care where you define your functions, only that they’re defined somewhere.

 
fn main() {
    println!("Hello, world!");

    another_function();
}

fn another_function() {
    println!("Another function.");
}

 
[root@itoracle functions]# cargo run
    Compiling functions v0.1.0 (/usr/local/automng/src/goapp/src/functions)                                               
     Finished dev [unoptimized + debuginfo] target(s) in 6.41s                                                            
      Running `target/debug/functions`
 Hello, world!
 Another function.

函数参数

 
In function signatures, you must declare the type of each parameter. 
This is a deliberate decision in Rust’s design: requiring type annotations in function definitions means 
the compiler almost never needs you to use them elsewhere in the code to figure out what you mean.

 
fn main() {
    another_function(5, 6);
}

fn another_function(x: i32, y: i32) {
    println!("The value of x is: {}", x);
    println!("The value of y is: {}", y);
}

 
[root@itoracle functions]# cargo run
    Compiling functions v0.1.0 (/usr/local/automng/src/goapp/src/functions)                                               
     Finished dev [unoptimized + debuginfo] target(s) in 3.03s                                                            
      Running `target/debug/functions`
 The value of x is: 5
 The value of y is: 6

函数体

 
Function bodies are made up of a series of statements optionally ending in an expression.

We’ve actually already used statements and expressions. 
Statements are instructions that perform some action and do not return a value. 
Expressions evaluate to a resulting value. Let’s look at some examples.
    
Creating a variable and assigning a value to it with the let keyword is a statement. let y = 6; is a statement.

 
fn main() {
    let y = 6;
}

 
Function definitions are also statements; the entire preceding example is a statement in itself.

Statements do not return values. 
Therefore, you can’t assign a let statement to another variable, 
as the following code tries to do; you’ll get an error:

 
fn main() {
    let x = (let y = 6);
}

 
[root@itoracle functions]# cargo run
    Compiling functions v0.1.0 (/usr/local/automng/src/goapp/src/functions)                                               
 error: expected expression, found statement (`let`)                                                                      
  --> src/main.rs:2:14                                                                                                    
   |                                                                                                                      
 2 |     let x = (let y = 6);                                                                                             
   |              ^^^ expected expression                                                                                 
   |                                                                                                                      
   = note: variable declaration using `let` is a statement                                                                
                                                                                                                          
 error: aborting due to previous error                                                                                    
                                                                                                                          
 error: Could not compile `functions`.                                                                                    
 
 To learn more, run the command again with --verbose.

 
The let y = 6 statement does not return a value, so there isn’t anything for x to bind to.

Expressions evaluate to something and make up most of the rest of the code that you’ll write in Rust. 
Consider a simple math operation, such as 5 + 6, which is an expression that evaluates to the value 11.
Expressions can be part of statements: 
The 6 in the statement let y = 6; is an expression that evaluates to the value 6. 

Calling a function is an expression. Calling a macro is an expression. 
The block that we use to create new scopes, {}, is an expression, for example

 
fn main() {
    let _x = 5;

    let _y = {
        let _x = 3;
        _x + 1
    };

    println!("The value of y is: {}", _y);
}

 
let y = {
    let x = 3;
    x + 1
};

 
is a block that, in this case, evaluates to 4. 
That value gets bound to y as part of the letstatement. 
Note the x + 1 line without a semicolon at the end, which is unlike most of the lines you’ve seen so far. 
Expressions do not include ending semicolons. If you add a semicolon to the end of an expression, 
you turn it into a statement, which will then not return a value. 
Keep this in mind as you explore function return values and expressions next.

 
[root@itoracle functions]# cargo run src/main.rs 
    Compiling functions v0.1.0 (/usr/local/automng/src/goapp/src/functions)                                               
     Finished dev [unoptimized + debuginfo] target(s) in 0.63s                                                            
      Running `target/debug/functions src/main.rs`
 The value of y is: 4

函数返回值

 
We don’t name return values, but we do declare their type after an arrow (->). 
In Rust, the return value of the function is synonymous with the value of the final expression in the block of the body of a function. You can return early from a function by using the return keyword and specifying a value, but most functions return the last expression implicitly. Here’s an example of a function that returns a value:

 
fn five() -> i32 {
    5
}

fn main() {
    let x = five();

    println!("The value of x is: {}", x);
}

 
[root@itoracle functions]# cargo run
Compiling functions v0.1.0 (/usr/local/automng/src/rust/test/functions)                                                                                                  
    Finished dev [unoptimized + debuginfo] target(s) in 4.96s                                                                                                               
    Running `target/debug/functio
    

 
There are two important bits: first, the line let x = five(); shows that we’re using the return value of a function to initialize a variable. 
Because the function five returns a 5, that line is the same as the following:

 
let x = 5;

 
Second, the five function has no parameters and defines the type of the return value, 
but the body of the function is a lonely 5 with no semicolon 
because it’s an expression whose value we want to return.

注意,函数体结束的时候没有分号“;”

 
fn main() {
    let x = plus_one(5);

    println!("The value of x is: {}", x);
}

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

 
[root@itoracle functions]# cargo run
    Compiling functions v0.1.0 (/usr/local/automng/src/rust/test/functions)                                                                                                  
     Finished dev [unoptimized + debuginfo] target(s) in 1.76s                                                                                                               
      Running `target/debug/functions`
 The value of x is: 6

如果不是在函数体最后一行返回,则可以使用return语句

 
fn main() {
    let mut x = plus_one(5);
    println!("The value of x is: {}", x);
    x = plus_one(15);
    println!("The value of x is: {}", x);
}

fn plus_one(mut x: i32) -> i32 {
    if x < 10 {
        return  10;
    }
    x = x + 10;
    x
}

 
[root@itoracle functions]# cargo run
    Compiling functions v0.1.0 (/usr/local/automng/src/rust/test/functions)                                                                                                  
     Finished dev [unoptimized + debuginfo] target(s) in 1.22s                                                                                                               
      Running `target/debug/functions`
 The value of x is: 10
 The value of x is: 25

另外,最后一句使用return语句也是可以的,但rust建议使用不加分号的表达式

 
fn main() {
    let mut x = plus_one(5);
    println!("The value of x is: {}", x);
    x = plus_one(15);
    println!("The value of x is: {}", x);
}

fn plus_one(mut x: i32) -> i32 {
    if x < 10 {
        return  10;
    }
    x = x + 10;
    return x;
}

 
[root@itoracle functions]# cargo run
    Compiling functions v0.1.0 (/usr/local/automng/src/rust/test/functions)                                                                                                  
     Finished dev [unoptimized + debuginfo] target(s) in 2.43s                                                                                                               
      Running `target/debug/functions`
 The value of x is: 10
 The value of x is: 25

没有返回值的函数

 
fn justgo(){
    println!("永远是多远?");
}
    

使用元组让函数返回多个值

 
fn testFnReturn() -> (u8,String){
    (1,"good".to_string())
}

 
let a = testFnReturn();
println!("{}",a.1);

函数定义后,必须被调用,不然运行时会给出警告

 
warning: function is never used: `justgo`                                                                              
-- src/main.rs:19:1                                                                                                 

 
如果不想一直看到该warning,可以在函数所在的文件第一行加入

#![allow(unused)]

参考