Rust 学习笔记2

Rust 初学笔记 2

本篇概要

本篇着力去记录了Rust最核心的内存管理机制“所有权”,Rust中两种非常重要的数据类型Struct和enum。

Rust 学习笔记1

3 Rust的所有权

3.1 初探所有权

  • Rust的核心功能之一:所有权

  • 与内存管理方式息息相关:通过所有权系统管理内存,编译器在编译时会根据一系列的规则进行检查。如果违反了任何这些规则,程序都不能编译。在运行时,所有权系统的任何功能都不会减慢程序。

  • 所有权规则

    所有权存在的意义,管理heap上的内存

    • rust中的每一个值都有一个所有者
    • 值在任一时刻有且只有一个所有者
    • 当所有者离开作用域,这个值将被丢弃
  • 变量作用域

    进入作用域有效,出作用域无效

  • Rust的内存回收机制

    {
    	let s =String::from ("hello");
    	//...
    }
    //当s出了其作用域的时候,自动调用内存处理机制,drop函数,将s进行销毁
    //s字符串是存储在堆上的
    
    • Rust永远不会自动进行深拷贝
    fn main() {
        let s1 = String::from("hello");
        let s2 = s1;
    
        println!("{}, world!", s1);
    }
    //当s1拷贝给s2的时候,s1自动丧失意义,因此代码会报错
    //为什么s1无效,是因为为了放置二次释放的问题
    
    • 深拷贝的方式,利用clone()
      • 当clone出现的时候,代码可能相当耗费资源
      • 但是当数据类型是整型的时候,拷贝的速度极快,因此这时候不再区分深浅拷贝,也就是和String的内存处理机制不同
    fn main() {
        let s1 = String::from("hello");
        let s2 = s1.clone();
    
        println!("s1 = {}, s2 = {}", s1, s2);
    }
    
    • Rust 不允许自身或其任何部分实现了 Drop trait 的类型使用 Copy trait。
  • 所有权和函数

    fn main() {
        let s = String::from("hello");  // s 进入作用域
    
        takes_ownership(s);             // s 的值移动到函数里 ...
                                        // ... 所以到这里不再有效
    
        let x = 5;                      // x 进入作用域
    
        makes_copy(x);                  // x 应该移动函数里,
                                        // 但 i32 是 Copy 的,
                                        // 所以在后面可继续使用 x
    
    } // 这里,x 先移出了作用域,然后是 s。但因为 s 的值已被移走,
      // 没有特殊之处
    
    fn takes_ownership(some_string: String) { // some_string 进入作用域
        println!("{}", some_string);
    } // 这里,some_string 移出作用域并调用 `drop` 方法。
      // 占用的内存被释放
    
    fn makes_copy(some_integer: i32) { // some_integer 进入作用域
        println!("{}", some_integer);
    } // 这里,some_integer 移出作用域。没有特殊之处
    
  • 返回值与作用域

    fn main() {
        let s1 = gives_ownership();         // gives_ownership 将返回值
                                            // 转移给 s1
    
        let s2 = String::from("hello");     // s2 进入作用域
    
        let s3 = takes_and_gives_back(s2);  // s2 被移动到
                                            // takes_and_gives_back 中,
                                            // 它也将返回值移给 s3
    } // 这里,s3 移出作用域并被丢弃。s2 也移出作用域,但已被移走,
      // 所以什么也不会发生。s1 离开作用域并被丢弃
    
    fn gives_ownership() -> String {             // gives_ownership 会将
                                                 // 返回值移动给
                                                 // 调用它的函数
    
        let some_string = String::from("yours"); // some_string 进入作用域。
    
        some_string                              // 返回 some_string 
                                                 // 并移出给调用的函数
                                                 // 
    }
    
    // takes_and_gives_back 将传入字符串并返回该值
    fn takes_and_gives_back(a_string: String) -> String { // a_string 进入作用域
                                                          // 
    
        a_string  // 返回 a_string 并移出给调用的函数
    }
    

    变量的所有权总是遵循相同的模式,将值赋给另一个变量时移动它

    可以使用元组来返回多个返回值

  • 引用

    不用获取所有权就可以使用值的功能

3.2 引用与借用

  • 引用就是使用这个对象但是并不拥有对象的所有权。
  • 将引用作为函数参数就叫做借用
  • 一个作用域,只能有一个可变引用
  • 一个作用域,不能同时拥有可变引用以及不可变引用(任意数量的不可变引用)
  • 不可以发生悬空指针(悬空引用)

3.3 Slice类型

  • 字符串切片
    • 指向字符串部分一部分的引用
    • format: [开始索引…结束索引] 结束索引应该大1
    • 从0开始可以不写
    • 结束索引是字符串结束,可以写s.len()
    • […]指的是引用所有的
    • &str 就是字符串切片,不可变的引用
  • 数组切片

4 结构体数据类型

4.1 结构体的定义和实例化

  • 自定义数据类型

    最后一个变量后面也要有,

struct User{
	username:String,
	year_old:u6,
	active:bool,
}
  • 字符串赋值可以打乱顺序,但是都得赋值
  • 字符串访问 user1.email
  • 一个字段可变,所有字段可变
  • 可以作为函数的返回值
  • 字符串的简写:当字段名和形式参数的名字相同时候,可以直接不写后面的名字
  • 可以基于某个struct来拆杆件一个新实例,就是把特殊的值进行赋值,其他的可以用 …structname进行赋值

4.1.1 Tuple struct

  • 整体有名字,但是局部没有名字
struct color(i32,i32,i32);
struct point(i32,i32,i32);

4.1.2 Unit-Like struct

  • 没有任何字段的struct

4.1.3 struct数据的所有权

  • struct 里面可以放引用
  • 但是引用需要配合生命周期使用

4.2 struct方法

将函数封装在struct里面,使用impl关键字进行封装。

struct Rectangle{
	width:u32,
	length:u32,
}

// 需要在impl块里面进行调用
impl Rectangle{
	fn area(&self) -> u32{
		self.width *self.length
	}
}

fn main(){
	let rect = Rectangle{
		width = 30,
		length = 15,
	};
	println!("{}",rect.area());
}
  • Rust可以自己解引用

  • 每个rust允许有多个关联函数

    4.2.1 关联函数

    第一个函数不是self

5 枚举和模式匹配

5.1 定义枚举

enum IPAddress{
	V4,
	V6,
}

let four = IP::V4;

let six = IP ::v6;

  • 可以作为struct的字段

  • 枚举类型可以嵌入任何类型的数据

    枚举类型可以关联结构体

enum IPAddress{
	V4(u8,u8,u8,u8),
	V6(String),
}

5.1.1 枚举方法

可以使用impl进行枚举方法的定义

5.2 Option枚举

  • 在预导入模块中

  • 某个值可能存在可能不存在

  • Rust里面没有null

    let absent_num : Option = None;

5.3 match

5.3.1 match方法的定义

// 起到一个匹配的作用
match coin{
	Coin::Penny =>{

	}
	Coin::Nickel =>{
	
	}
	Coin::Dime =>{
		
		}
}

5.3.2 绑定值的模式匹配

enum里面嵌套enum,但是使用一个并不是很明确的state来进行替代,这样最后就可以利用state了

5.3.3 match匹配的规则

  • match匹配的时候必须穷举所有的可能,就是所有的模式都要有结论
  • 剩下的可以用 _ ⇒ (),进行替代

5.4 if let

  • 只针对一种模式进行匹配
  • 放弃了穷举的可能
  • if let {} else{}
  • 19
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

GritNotGift

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

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

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

打赏作者

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

抵扣说明:

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

余额充值