IT技术之家

首页 > 编程

编程

Rust学习3_String vs Array

发布时间:2023-11-28 22:14:30 编程 33次 标签:rust
Struct结构体什么是Struct: 结构体, 一种自定义的数据类型,为相关联的值命名、打包,使之成为有意义的组合。定义与实例化使用struct 关键字, 并未整个Struct命名利用花括号为所有字段(Field) 定义名称与类型,用逗号隔开。struct Student { name: String, school: String, hobby:Vec<String>, age: u8,}Struct既然被定义了,那肯定要实例化不然...

Struct结构体

什么是Struct: 结构体, 一种自定义的数据类型,为相关联的值命名、打包,使之成为有意义的组合。

定义与实例化

使用struct 关键字, 并未整个Struct命名

利用花括号为所有字段(Field) 定义名称与类型,用逗号隔开。

struct Student {
    name: String,
    school: String,
    hobby:Vec<String>,
    age: u8,
}

Struct既然被定义了,那肯定要实例化不然没有办法被使用:

Struct实例化需要为所有字段指定具体值无须按照声明顺序进行指定,使用:赋值, 用.方法取值struct 的示例也默认不可变,我们需要用mut在实例化时设置可变。一旦Struct的实例可变,那示例中的所有字段可变
fn main() {
    let mut student1 = Student{
        name: String::from("老王"),
        school:String::from("非人一中"),
        hobby:vec!(String::from("Python"), String::from("Rust")),
        age:10,
    };
    student1.age += 1;
    println!("The student name is {},age is {}", student1.name, student1.age);
}
The student name is 老王,age is 11

Struct 调试输出,我们没有办法直接输出struct, 因为Struct这种结构本身不具有Display这个trait, 就类似于Python的__ str __()方法,我们看一下报错信息

println!("{}", student1);
19 |     println!("{}", student1);
   |                    ^^^^^^^^ `Student` cannot be formatted with the default formatter
   |
   = help: the trait `std::fmt::Display` is not implemented for `Student`
   // 很有意思的这一句他给了我们一个修复方案,那我们尝试一下
   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
   = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
19 |     println!("{:?}", student1);
   |                      ^^^^^^^^ `Student` cannot be formatted using `{:?}`
   |
   = help: the trait `Debug` is not implemented for `Student`
   // 又给了新的报错信息,那我们再跟着尝试一下
   = note: add `#[derive(Debug)]` to `Student` or manually `impl Debug for Student`
   = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
// 这句话的意思是Student这个结构体派生于Debug这个宏,算了,这些概念后面会提到我现在也不知道呜呜呜
#[derive(Debug)]
struct Student {
    name: String,
    school: String,
 。。。。。
 
 //运行, 成功打印了类json的数据格式,那么之后调错也会很方便的
 Student { name: "老王", school: "非人一中", hobby: ["Python", "Rust"], age: 10 }

实例化部分参数传参的使用权

因为我们上一部分学了所有权相关的东西,那么如果我们把实例化的一部分属性以实参传递给函数(不使用引用与使用引用)会发生什么呢?

// 例子一,直接传递参数
fn main() {
    let mut student1 = Student{
        name: String::from("老王"),
        school:String::from("非人一中"),
        hobby:vec!(String::from("Python"), String::from("Rust")),
        age:10,
    };
    grow_up_a_year(student1.age);
    println!("The student name is {},age is {}", student1.name, student1.age);
}

fn grow_up_a_year(mut age:u8){
    age += 1;
    println!("We grow up a year, now we age is {}", age);
}
We grow up a year, now we age is 11
The student name is 老王,age is 10

可以看到我们虽然把student1.age传递给了函数grow_up_a_year, 但是我们并没有丧失student的使用权,换句话说即使我们传递单个参数的使用权也无法夺走结构体的使用权。

//例子2, 传递整个结构体
fn main() {
    let mut student1 = Student{
        name: String::from("老王"),
        school:String::from("非人一中"),
        hobby:vec!(String::from("Python"), String::from("Rust")),
        age:10,
    };
    grow_up_a_year(student1);
    println!("The student name is {},age is {}", student1.name, student1.age);
}

fn grow_up_a_year(mut student1:Student){
    student1.age += 1;
    println!("We grow up a year, now we age is {}", student1.age);
}
17 |     println!("The student name is {},age is {}", student1.name, student1.age);
   |                                                                 ^^^^^^^^^^^^ value borrowed here after move

这个结果是比较符合预期的,应为我们传参数的时候就把结构体的所有权传送出去了,在main中的结构体会被删掉。

//例子3, 动态引用结构体参数传递
fn main() {
    let mut student1 = Student{
        name: String::from("老王"),
        school:String::from("非人一中"),
        hobby:vec!(String::from("Python"), String::from("Rust")),
        age:10,
    };
    grow_up_a_year(& mut student1.name);
    println!("The student name is {},age is {}", student1.name, student1.age);
}

fn grow_up_a_year(mut name:& mut String){
   *name  = String::from("老王很强");
    println!("We change the name , now new name is {}", name);
}
We change the name , now new name is 老王很强
The student name is 老王很强,age is 10

字符串时可以用也能用可变引用修改,但是我想用add方法的时候又不知道为什么不让我调用,不过这些都是String学习的后话了。 所以说,我们用可变引用传递成功修改了变量,,我估计我们直接引用传递结构体也是这个结果,下面事实证明没什么差别。

fn main() {
    let mut student1 = Student{
        name: String::from("老王"),
        school:String::from("非人一中"),
        hobby:vec!(String::from("Python"), String::from("Rust")),
        age:10,
    };
    grow_up_a_year(& mut student1);
    println!("The student name is {},age is {}", student1.name, student1.age);
}

fn grow_up_a_year(mut studenta:& mut Student){
    (*studenta).age += 1;
    //*(studenta.age) += 1;  错误写法:type `u8` cannot be dereferenced
    println!("I grow up one year")
}
I grow up one year
The student name is 老王,age is 11

综上,我们可以得到Struct的使用权情况,函数直接传Struct内部参数的时候并没有夺走整个实例化Struct的使用权,所以我们在实例化Struct的作用域中依然可以调用Struct并用.标记法获取其参数。但是我们一旦传参整个Struct实例就会时区所有权在其作用域重实效。同时Struct支持参数和实例本身的可变引用

struct更新

Struct更新是指基于某个struct实例来创建一个新实例(部分值相同,部分值不同):

let student2 = Student{
    name:String::from("小白"),
    hobby:vec!(String::from("Go"), String::from("JavaScript")),
    .. student1
}
//更改了两项,但是剩下两项与student1相同

Tuple Struct

我们可以用结构体定义类Tuple结构(话说回来好像真的是这样,因为tuple不限元素类型)。不同的是Tuple中的具体元素没有变量名承载,所以必须用位置来表示以防止出现赋值或者更新出错的结果.

// 简单例子
struct Color(u8,u8,8);
let rgb = Color(0,0,0)

Unit-Like Struct ( 没有任何字段)

类似于() ,一个空结构体,主要作用是在某个类型无数据存储的上实现trait(虽然很明显我们现在还没接触到)

方法

没想到吧, Struct中还可以写方法,那Rust里的Struct已经可以看作是class了(误)

Rust中的方法与函数的异同:

方法与函数类似,都使用fn关键字, 名称,参数,返回值方法在struct(或enum, trait对象)的上下文定义方法的第一个参数是self, 表示方法被调用的struct实例
//一个例子,一个长方形的结构体,其面积应该等于其两个边长的乘积
struct square {
    bianchang1: i32,
    bianchang2: i32,
    mianji:i32,
}
impl square{
    fn cal_mianji(& mut self){
        //这里这么写 self.mianji = self.bianchang1 * self.bianchang2;
        //也可以, 主要是这是数字类型的就问题不大哦。
        (*self).mianji = (*self).bianchang1 * (*self).bianchang2;
    }
}
//
fn main() {
    let mianji = cal_space_of_square();
    println!("长方形面积是{}", mianji)
}

fn cal_space_of_square() -> i32 {
    let mut m: String = String::new();
    let mut bian1: i32;
    let mut bian2: i32;
    println!("请输入边长1");
    stdin().read_line(&mut m).expect("读取失败");
    loop {
        match m.trim().parse() {
            Ok(m) => {
                bian1 = m;
                break;
            }
            Err(_) => {
                println!("失败,请重新输入边长1");
                stdin().read_line(&mut m).expect("读取失败");
                continue;
            }
        };
    };
    println!("请输入边长2");
    let mut n = String::new();
    stdin().read_line(&mut n).expect("读取失败");
    loop {
        match n.trim().parse() {
            Ok(n) => {
                bian2 = n;
                break;
            }
            Err(_) => {
                println!("失败,请重新输入边长2");
                stdin().read_line(&mut m).expect("读取失败");
                continue;
            }
        };
    };
    let mut sq = square{
        bianchang1: bian1,
        bianchang2:bian2,
        mianji:0,
    };
    sq.cal_mianji();
    sq.mianji
}
请输入边长1
15
请输入边长2
20
长方形面积是300

枚举 Enum

先来一份热腾腾的定义:枚举语序我们列举所有可能的值里定义一个类型

枚举的定义

enum关键字 + 枚举的名字 + { Options1, Options2 …}利用我们定义的枚举可以创建枚举值: let var1 = 枚举的名字::Options1.**枚举的变体都位于标识符的命名空间下,使用两个::进行分割。在rust中允许数据附加到枚举的变体中,可以无需定义Struct, 由我们定义的枚举类型本身存储数据,同时每个变体拥有不同类型以及关联的数据量
#[derive(Debug)]
enum Sex{
    male(Vec<String>),
    female(Vec<String>),
}

fn main() {
    let mut boy = Sex::male(vec![String::from("dicks"),String::from("Adam's apple ")]);
    let girl = Sex::female(vec![String::from("burst"),String::from("Menstrual cycle:")]);
    print!("{:#?}", boy);
}
male(
    [
        "dicks",
        "Adam's apple ",
    ],
)
我们甚至可以位枚举定义方法,使用Impl关键字定义方法.所以说枚举是Rust最强数据结构
impl Sex {
    fn normal_fn(& mut self) {
       println!("I'm used");
    }
}
let mut boy = Sex::male(vec![String::from("dicks"),String::from("Adam's apple ")]);
boy.normal_fn();
I'm used

Option枚举

Option定义于标准库中,并且会与导入(我们不需要主动引入), 描述了某个值可能存在(某种类型)或不存在的情况