长沙建立企业网站,金融行业做网站需要什么,网站群建设的目的,门户网站开发注意哪些rust在内存资源管理上采用了#xff08;先进优秀#xff1f;算吗#xff09;但特立独行的设计思路#xff1a;所有权。这是rust的核心#xff0c;贯穿在整个rust语言的方方面面#xff0c;并以此为基点来重新思考和重构软件开发体系。 涉及到的概念点#xff1a;借用先进优秀算吗但特立独行的设计思路所有权。这是rust的核心贯穿在整个rust语言的方方面面并以此为基点来重新思考和重构软件开发体系。 涉及到的概念点借用引用生命周期 借用borrowing
这里就要谈到这篇文章的主题也是rust绕不开的主题所有权。 所有权模型Rust 的所有权模型允许值在内存中有唯一的所有者 一开始我以为引用就是其他语言如go里常见的引用, 而借用是更在引用之上的一种抽象是对我们【使用引用去达到目的】这种行为的抽象 。因为我看到在一些教程里直接将两者等同混用但其实是不对的 因为Rust语言中的引用和其他语言中的引用不一样其他语言里的引用是变量的别名Rust语言中的引用是指向某个值的指针而不是别名。在其他语言中引用就相当于拿到了值的别名跟原来的值是同一个东西可以进行任何无差别访问。在Rust语言中的借用都是临时借用使用权并不破坏单一所有权原则。
“借用” 是指通过引用来访问值而不获取所有权; Rust 使用 “借用” 这个术语来强调在借用期间被借用的值的仍然归原所有者所有并且原所有者在借用期间仍然保持可变性和原始值的所有权。 就好比我从你那里借了一本书但我肯定不能随意在上面乱写乱画因为书还是归你所有。所以Rust的借用默认是不可变的如果想要修改借用的值需要显示的声明使用可变借用mut x取得书主人的授权。
通过借用而不是其他语言中的直接引用可以确保在借用期间只有一个可变或不可变的访问者避免了悬空指针和内存安全问题。
Rust里的借用没有开辟单独的表现方式形式上仍然是其他语言里引用的样子在rust里以 变量前加“”符来表示不可变借用例如x 用mut 表示可变借用,例如:mut x。
从能力范围上来看 借用包含了传统意义上的引用但是能力范围又大于引用。注意这个图只是从能力范围上来看可变借用和传统引用好像一样本质还是不同的即可变借用没有获取原始变量的所有权就好比我租了你的房子谈好条件可以让我装修但房子还是你的但在我装修房子后你再给别的租客别的借用来看这个房子的时候 这个房子会是装修好后的样子。 借用的限制 为了保证内存安全Rust语言中的借用也有一些限制比如
在同一作用域中同一数据只能有一个可变借用即多个可变借用不能同时存在更准确是同一所有权型变量的多个可变借用作用域不能交叠。在同一个作用域中同一数据可以有多个不可变借用。在一个作用域中可变借用与不可变借用不能同时存在 (更准确是可变借用与不可变借用的作用域不能交叠)所有借用的生命周期不能超出值的生命周期防止悬垂指针保证内存安全。在有借用包括可变借用和不可变借用存在的情况下不能通过原所有权型变量对值进行更新。当借用完成后借用变量的作用域结束物归原主才又可以使用所有权型变量对值做更新操作了。
fn main(){let mut a 10u32;let b a;a 50;println!({b})
}
-----------------------
fn main(){let mut a 10u32;let b mut a;a 50;println!({b})
}
两个例子都不能通过编译另外有个格外的要单独说明的点可变引用的再赋值会执行移动操作而不是复制赋值后原来那个可变引用的变量就不能用了。可以看出一个☝️所有权型变量的可变引用也具有所有权特征。
多级可变引用
对于多级可变引用要利用可变引用去修改目标资源值的时候需要做正确的多级解引用操作比如两级引用就要对应两级接引用。而且这个引用过程中必须保证全是可变引用才可以修改到目标资源的值。
对于多级引用的打印语句可以为我们自动接引用到正确的层数直至访问到目标资源值。这很符合人的意图和业务需求。
在这里有个有意思的对比
go:
func main() {var a 10var b afmt.Println(a)//output:10fmt.Println(b)//output:0x... (memory address )
}rust:
fn main() {let a 10u32;let b a;let c a;println!(a)//output:10println!(b)//output:10 println!(c)//output:10
}
可以看到rust像gpt一样识别到了我们的人类意图没有打印的引用的内存地址而是打印了被引用对象的值。事实上哪怕是像let c a这种对a的多级引用rust也仍然正确获取了a的值。
触发所有权转移的行为 会触发所有权转移的行为有赋值操作函数入参函数返回值集合操作中的移动如Vec、HashMap等迭代器中的移动 先来看一个列子
fn main() {let s String::from(rust);let s1 s; // s的所有权转移给了s1, s不再有效// println!({}, s); // 此处会报错因为s已经不再有效println!({}, s1);// s1释放
}上面的例子中当把s赋值给s1时s的所有权转移到了s1s不再有效也就是Move语义以确保字符串rust在同一时刻只能有一个所有者。当s1离开作用域时s1的所有权释放字符串rust也随之释放。 再来看下边一个
fn main(){let a 10u32;let b a;println!({a});// 此处不会报错此时a和b都是有效的// a 释放println!({b});// b 释放
}为什么字符串的复制会报错 而整数类型不会报错呢 这是因为Rust对简单数据类型做了处理。假如整型、浮点型、布尔型等这都需要转移所有权那这程序编写起来也太复杂了吧。所以Rust语言对于这些简单数据类型采用了Copy trait来实现这样就是复制而不是转移所有权。在上边的例子中因为a是简单数据类型采用了Copy trait所以a和b都是有效的。 实现了Copy trait的类型在赋值或者传参时值会自动按位拷贝而对于没有实现Copy trait的类型会采用Move转移所有权的方式来传递数据。
实现了Copy trait的类型
原生类型整型(i8,u8,i16,u16,i32,u32,i64,u64,i128,u128,isize,usize)、浮点型(f32,f64)、布尔型、字符型(char)、单元类型()、Never Type(!)。不可变引用(T)函数指针裸指针(*const T, *mut T)数组[T;N]、元组(T1, T2, …, Tn)、Option类型(需要注意的是只有当它们的元素类型都实现了Copy trait时它们才实现了Copy trait)。
对于复合类型比如枚举体和结构体Rust语言默认是不实现Copy trait的但是如果这些类型的所有成员都实现了Copy trait那么你可以手动添加#[derive(Copy, Clone)]来实现Copy trait。如果内部结构包含Move语义的类型那么就无法实现Copy trait。