cargo basic

cargo new objname 创建项目

cargo run 运行项目

cargo install –force –path . 安装 .目录下的项目,将编译好的二进制文件拷贝到~/.cargo/bin中

变量绑定

Rust 中,使用关键字 let 声明变量。

let x = 5;

在 Rust 中,变量默认是不可改变的(immutable),当变量不可变时,一旦值被绑定到一个名称上,这个值就不能被改变,这样的设计有助于防止意外的数据修改和并发问题。若

要使得变量可变,需要在声明时使用 mut 关键字。

let mut x = 5;
x = 10;

常量

Rust 中常量总是不可变,声明常量使用 const 关键字而不是 let。

常量只能被声明为常量表达式,而不可以是其他任何只能在程序运行时计算出的值。

常量定义时候需要指定类型

const xx:i32 = 15;

标量类型

• 有符号整数(signed integers):i8、i16、i32、i64、i128 和 isize(指针宽度)

• 无符号整数(unsigned integers): u8、u16、u32、u64、u128 和 usize(指针宽度)

• 浮点数(floating point): f32、f64

• char(字符):单个 Unicode 字符,如 ‘a’,’α’ 和 ‘∞’(每个都是 4 字节)

• bool(布尔型):只能是 true 或 false

• 单元类型(unit type):()。其唯一可能的值就是 () 这个空元组

复合类型

数组

数组的类型定义为 [元素类型;元素数量] 在初始化时可以对每个元素都做一遍初始化[1,2,3,4,5],也可以用[值;数量]来做批量的初始化

let array:[i32;5] = [5;5];

数组的操作

array[0] //访问元素
array[0] = 1; //写数据 注意必须是通过mut关键字创建的数组才支持写数据

元组

let tup:(i32,i32,i32) = (1,2,3);

元组的成员是可以修改的,通过tup.0 tup.1 点+成员下标来访存

let mut tup:(i32,i32,i32) = (1,2,3);
tup.0 = 10;
println!("is {}",tup.0);

使用模式匹配解构元组

let mut tup:(i32,i32,i32) = (1,2,3); // 元组的定义
tup.0 = 10; // 访问 读写元组的元素,通过 元组名.idx去访问
println!("is {}",tup.0);
let (a,b,c) = tup; //模式匹配可以解构元组的值,将元组的值分配到几个变量上

函数定义

fn function_name() -> return_tpye{
do_someting
}

if表达式

if不需要写括号

if a > b {
}

if是一个表达式还可以有返回值 用于变量绑定语句

let if_a = if 1> 0 {100} else {10};
    println!("{}",if_a);

loop循环

loop 关键字告诉 Rust 一遍又一遍地执行一段代码直到你明确要求停止。

可以通过continue跳过单次循环,可以通过break退出循环

let mut i = 100;
    loop {
        println!("{}",i);
        i = i - 1;
        if i < 1 {
            break;
        }
    }

loop表达式有返回值就像if一样

let mut i = 100;
    let s = loop {
        println!("{}",i);
        i = i - 1;
        if i < 1 {
            break 100;
        }
    };
    println!("{}",s);

循环标签

loop可以存在循环标签,可以通过break和continue跳转到某个标签中,一般用于多层loop的情况

'loop1 : loop {
        println!("loop1");
        'loop2 : loop {
            println!("loop2");
            break 'loop1;
        }
    }

在loop关键字前使用 ‘循环标签名字 : 这样的表达式就可以给循环打标签,在break中需要 ‘循环标签名来实现跳转到某个loop循环标签中

while循环

let mut i = 0;
    while i < 10 {
        i = i + 1;
        println!("i is{}",i)
    }

while循环循环条件那没有括号,没有返回值0

for循环

for循环似乎主要用于遍历迭代器,实现了可迭代trait的对象就可以用for去迭代?

for i in 1..5{
        println!("{}",i);
}

迭代数组

let test_array:[i32;10] = [2;10];
    for i in test_array {
        println!("{}",i);
}

所有权(ownership)

定义:

Rust 中的每一个值都有一个所有者(owner)

值在任一时刻有且只有一个所有者

当所有者(变量)离开作用域,这个值将被丢弃

如果某个对象实现了copy trait 在进行变量绑定操作时候会直接复制对象的值过去,而不是会转移所有权

所有权机制就是为了保证在某一段时间内,某个值只有一个所有者,为了避免数据竞争

这个表达式的行为是 将123绑定到符号x,然后再次绑定到y中,由于值在任意时刻只有一个所有者,x会被丢弃

let x = 123;
let y = x;

变量隐藏

这个样例中 第一个变量被第二个 隐藏(Shadowing) 了

fn main() {
    let x = 5;
    let x = x + 1;
    {
    let x = x * 2;
    println!("The value of x in the
    inner scope is: {x}");
    }
    println!("The value of x is: {x}");
}

函数传参会转移所有权

s作为参数传递到 test函数时,所有权被转移到test中

fn test(a:String) -> String {
    return a;
}

fn main() {
    let s = String::from("hello");
    test(s);
    println!("{}",s);
}

函数返回值也会转移所有权

引用和借用

引用(reference)像一个指针,因为它是一个地址,我们可以由此访问储存于该地址的属于其他变量的数据。 与指针不同,引用确保指向某个特定类型的有效值,我们将创建一个引用的行为称为 借用(borrowing)。

传递引用并不会转移所有权

fn test(a:&String){
    println!("{}",a);
}

fn main() {
    let s = String::from("hello");
    test(&s);
    println!("{}",s);
}

可变引用

可变引用可以在引用的基础上传递一个可以读写数据的”指针”,而不转移数据的所有权

同一作用域下可以存在多个对于同一对象的不可变引用,但是不能存在多个对于同一对象可变引用,不然可能会产生数据竞争,也不能同时存在对于同一对象的可变引用和不可变引用

fn test(a:&mut String){
    a.push_str("AAAAAAA");
    println!("{}",a);
}

fn main() {
    let mut s  = String::from("hello");
    test(&mut s);
    println!("{}",s);
}

String类型

String类型支持两种创建方式

通过String::from创建 通过”aaa”.to_string() 字符串字面量类型转换创建

fn main() {
    let s1 = String::from("tests1");
    let s2 = "tests2".to_string();
    println!("{}",s1);
    println!("{}",s2);
}

slice类型

slice可以创建一个针对某个集合的一段不可变引用,它并没有获取这段数据的所有权

fn main() {
    let a = [1, 2, 3, 4, 5];
    let slice = &a[1..3];
    

    let str = String::from("test_str1");
    let str2 = &str[0..3];

    println!("{}",str2);


}

struct结构体

struct的创建方式是 struct 结构体名然后在花括号里面定义结构体有的字段

struct test_struct {
    a: i32
    b: i64
}

结构体实例创建,访问字段

struct User{
    Username:String,
    Password:String
}



fn main() {

    let mut User1 = User{
        Username : "User1".to_string(),
        Password : "123456".to_string()
    };


    User1.Username = String::from("User2");
    println!("{}",User1.Username);

}

元组结构体

元组结构体也是一种能将不同数据绑定在一起的一个复合类型,和结构体的区别是元组结构体的成员没有一个具体的字段名

元组结构体的创建 struct 元组结构体名 然后在圆括号中定义数据成员

struct Color(i32,i32,i32);


fn main() {

    let mut black = Color(255,255,255);
    println!("{}",black.0);

    black.0 = 0;
    println!("{}",black.0);


}

rustlings Exercise

variables §3.1

functions §3.3

if §3.5

primitive_types §3.2, §4.3

vecs §8.1

move_semantics §4.1, §4.2

structs §5.1, §5.3

strings §8.2

struct1

// structs1.rs
//
// Address all the TODOs to make the tests pass!
//
// Execute `rustlings hint structs1` or use the `hint` watch subcommand for a
// hint.

// I AM NOT DONE

struct ColorClassicStruct {
    // TODO: Something goes here
    red:u8,
    green:u8,
    blue:u8
}

struct ColorTupleStruct(/* TODO: Something goes here */u8,u8,u8);

#[derive(Debug)]
struct UnitLikeStruct;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn classic_c_structs() {
        // TODO: Instantiate a classic c struct!
        // let green =

        let green:ColorClassicStruct = ColorClassicStruct{
            red:0,
            green:255,
            blue:0
        };
        assert_eq!(green.red, 0);
        assert_eq!(green.green, 255);
        assert_eq!(green.blue, 0);
    }

    #[test]
    fn tuple_structs() {
        // TODO: Instantiate a tuple struct!
        // let green =
        let green = ColorTupleStruct(0,255,0);
        assert_eq!(green.0, 0);
        assert_eq!(green.1, 255);
        assert_eq!(green.2, 0);
    }

    #[test]
    fn unit_structs() {
        // TODO: Instantiate a unit-like struct!
        // let unit_like_struct =
        let unit_like_struct = UnitLikeStruct{};
        let message = format!("{:?}s are fun!", unit_like_struct);

        assert_eq!(message, "UnitLikeStructs are fun!");
    }
}

struct2

// structs2.rs
//
// Address all the TODOs to make the tests pass!
//
// Execute `rustlings hint structs2` or use the `hint` watch subcommand for a
// hint.

#[derive(Debug)]
struct Order {
    name: String,
    year: u32,
    made_by_phone: bool,
    made_by_mobile: bool,
    made_by_email: bool,
    item_number: u32,
    count: u32,
}

fn create_order_template() -> Order {
    Order {
        name: String::from("Bob"),
        year: 2019,
        made_by_phone: false,
        made_by_mobile: false,
        made_by_email: true,
        item_number: 123,
        count: 0,
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn your_order() {
        let order_template = create_order_template();
        // TODO: Create your own order using the update syntax and template above!
        // let your_order =

        let mut your_order = Order {
            name : String::from("Hacker in Rust"),
            year : 2019,
            made_by_phone : false,
            made_by_mobile : false,
            made_by_email : true,
            item_number : 123,
            count : 1

        };

        assert_eq!(your_order.name, "Hacker in Rust");
        assert_eq!(your_order.year, order_template.year);
        assert_eq!(your_order.made_by_phone, order_template.made_by_phone);
        assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile);
        assert_eq!(your_order.made_by_email, order_template.made_by_email);
        assert_eq!(your_order.item_number, order_template.item_number);
        assert_eq!(your_order.count, 1);
    }
}

struct3

https://kaisery.github.io/trpl-zh-cn/ch05-03-method-syntax.html

结构体方法定义

结构体方法类似于函数,也是使用fn xxname来定义,不同的地方是他们第一个参数总是 &self 或者 &mut self 用于代表该方法的实例

为某个结构体添加结构体方法通过 impl语法块实现

impl struct_name {

fn xxfunc(&self or &mut self){

dosometing

}

}

e.g.

struct Rectangle {
    width:u32,
    height:u32
}

impl Rectangle {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}
// structs3.rs
//
// Structs contain data, but can also have logic. In this exercise we have
// defined the Package struct and we want to test some logic attached to it.
// Make the code compile and the tests pass!
//
// Execute `rustlings hint structs3` or use the `hint` watch subcommand for a
// hint.

// I AM NOT DONE

#[derive(Debug)]
struct Package {
    sender_country: String,
    recipient_country: String,
    weight_in_grams: i32,
}

impl Package {
    fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package {
        if weight_in_grams <= 0 {
            panic!("Can not ship a weightless package.")
        } else {
            Package {
                sender_country,
                recipient_country,
                weight_in_grams,
            }
        }
    }

    // fn is_international(&self) -> ??? {
    //     // Something goes here...
    // }

    fn is_international(&self) -> bool {
        if self.sender_country == "Canada"{
            false
        }
        else{
            true
        }
    }

    // fn get_fees(&self, cents_per_gram: i32) -> ??? {
    //     // Something goes here...
    // }

    fn get_fees(&self, cents_per_gram: i32) -> i32 {
        self.weight_in_grams * cents_per_gram
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[should_panic]
    fn fail_creating_weightless_package() {
        let sender_country = String::from("Spain");
        let recipient_country = String::from("Austria");

        Package::new(sender_country, recipient_country, -2210);
    }

    #[test]
    fn create_international_package() {
        let sender_country = String::from("Spain");
        let recipient_country = String::from("Russia");

        let package = Package::new(sender_country, recipient_country, 1200);

        assert!(package.is_international());
    }

    #[test]
    fn create_local_package() {
        let sender_country = String::from("Canada");
        let recipient_country = sender_country.clone();

        let package = Package::new(sender_country, recipient_country, 1200);

        assert!(!package.is_international());
    }

    #[test]
    fn calculate_transport_fees() {
        let sender_country = String::from("Spain");
        let recipient_country = String::from("Spain");

        let cents_per_gram = 3;

        let package = Package::new(sender_country, recipient_country, 1500);

        assert_eq!(package.get_fees(cents_per_gram), 4500);
        assert_eq!(package.get_fees(cents_per_gram * 2), 9000);
    }
}

String1

// strings1.rs
//
// Make me compile without changing the function signature!
//
// Execute `rustlings hint strings1` or use the `hint` watch subcommand for a
// hint.

fn main() {
    let answer = current_favorite_color();
    println!("My current favorite color is {}", answer);
}

fn current_favorite_color() -> String {
    "blue".to_string()
}

String2

// strings2.rs
//
// Make me compile without changing the function signature!
//
// Execute `rustlings hint strings2` or use the `hint` watch subcommand for a
// hint.


fn main() {
    let word = String::from("green"); // Try not changing this line :)
    if is_a_color_word(&word) {
        println!("That is a color word I know!");
    } else {
        println!("That is not a color word I know.");
    }
}

fn is_a_color_word(attempt: &str) -> bool {
    attempt == "green" || attempt == "blue" || attempt == "red"
}

String3

// strings3.rs
//
// Execute `rustlings hint strings3` or use the `hint` watch subcommand for a
// hint.

// I AM NOT DONE

fn trim_me(input: &str) -> String {
    // TODO: Remove whitespace from both ends of a string!
    input.trim().to_string()
}

fn compose_me(input: &str) -> String {
    // TODO: Add " world!" to the string! There's multiple ways to do this!
    let mut result = input.to_string();
    result.push_str(" world!");
    result
}

fn replace_me(input: &str) -> String {
    // TODO: Replace "cars" in the string with "balloons"!
    let result = input.replace("cars", "balloons");
    result
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn trim_a_string() {
        assert_eq!(trim_me("Hello!     "), "Hello!");
        assert_eq!(trim_me("  What's up!"), "What's up!");
        assert_eq!(trim_me("   Hola!  "), "Hola!");
    }

    #[test]
    fn compose_a_string() {
        assert_eq!(compose_me("Hello"), "Hello world!");
        assert_eq!(compose_me("Goodbye"), "Goodbye world!");
    }

    #[test]
    fn replace_a_string() {
        assert_eq!(replace_me("I think cars are cool"), "I think balloons are cool");
        assert_eq!(replace_me("I love to look at cars"), "I love to look at balloons");
    }
}

String4

// strings4.rs
//
// Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your
// task is to call one of these two functions on each value depending on what
// you think each value is. That is, add either `string_slice` or `string`
// before the parentheses on each line. If you're right, it will compile!
//
// No hints this time!

// I AM NOT DONE

fn string_slice(arg: &str) {
    println!("{}", arg);
}
fn string(arg: String) {
    println!("{}", arg);
}

fn main() {
    string_slice("blue");
    string("red".to_string());
    string(String::from("hi"));
    string("rust is fun!".to_owned());
    string_slice("nice weather".into());
    string(format!("Interpolation {}", "Station"));
    string_slice(&String::from("abc")[0..1]);
    string_slice("  hello there ".trim());
    string("Happy Monday!".to_string().replace("Mon", "Tues"));
    string("mY sHiFt KeY iS sTiCkY".to_lowercase());
}
⬆︎TOP