"首次提交"
This commit is contained in:
1
ownership/.gitignore
vendored
Executable file
1
ownership/.gitignore
vendored
Executable file
@ -0,0 +1 @@
|
||||
/target
|
8
ownership/Cargo.toml
Executable file
8
ownership/Cargo.toml
Executable file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "ownership"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
146
ownership/src/main.rs
Executable file
146
ownership/src/main.rs
Executable file
@ -0,0 +1,146 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
ownership1();
|
||||
ownership2();
|
||||
ownership3();
|
||||
ownership4();
|
||||
ownership5();
|
||||
}
|
||||
|
||||
// rust 所有权系统
|
||||
// Rust 使用所有权系统来管理来自heap上的内存,
|
||||
// 1. 减少数据竞争,实现类似读写锁的机制
|
||||
// 2. 避免提前free,double free,悬垂引用等内存问题。
|
||||
fn ownership1(){
|
||||
/* 对于实现了Copy trait 的类型,rust会在赋值的时候直接copy一份给到新的变量,
|
||||
* 这样使得新的变量和现有的变量可同时使用,互不影响
|
||||
*/
|
||||
//将45绑定到num上
|
||||
let num = 45;
|
||||
//使用i32的Copy 将值拷贝并绑定到num1上
|
||||
let num1 = num;
|
||||
println!("num is {}, num1 is {}", num, num1);
|
||||
/* 实现了Copy trait的类型有:
|
||||
* 1. i32 u32 f32 char 等基本数据类型
|
||||
* 因为这些类型简单,往往都是存在stack上的,基本不会因为Copy trait影响性能
|
||||
* 但是如果是复杂的类型。比如一个动态可以变化的数组,字符串那么其如果每赋值一次都完整copy性能损失过大,
|
||||
* 所以其一般在赋值时都只是将地址和一些长度信息进行赋值给新变量,而内容都指向同一块内存地址。
|
||||
* 这样就会导致如果一个修改了里面的内容或者释放了这段内存,另外一个变量的访问将变得特别危险。
|
||||
*/
|
||||
}
|
||||
|
||||
fn ownership2(){
|
||||
/* 对于没有实现Copy trait 的类型: 同一时间只能归属于一个变量,
|
||||
所以当使用一个变量赋值给另外一个变量的时候前一个变量的就被shadow掉了,无法再使用,
|
||||
如果再使用就会编译出错。
|
||||
*/
|
||||
let mut str1 = String::new();
|
||||
str1.push_str("This is a string");// 通过str1操作字符串,添加一串字符串到String里
|
||||
let mut str2 = str1; // 将所有权移交给str2
|
||||
//此处String对象的所有权已经从str1移交给了str2,此时已经不能再通过str1去访问(读)或者修改(写)字符串了
|
||||
//str1.push_str("owner is not str1, can access string") //写
|
||||
//println!("{}", str1); //读
|
||||
str2.push_str("owner is str2");
|
||||
println!("{}", str2);
|
||||
|
||||
/* 这里的String就是一个没有copy trait的类型,其会在heap上申请一段内存存放字符串,
|
||||
* 而变量str1或者str2是在stack上的,他们均是记录其相关信息的载体,但是字符串实体还是在heap上。
|
||||
* 如上的示例里面可以看出,rust通过所有权的机制,确保同一时间只能有一个所有者可以操作字符串,
|
||||
* 如果所有权移出去那么就不再有访问的权利,也就存在读写,释放的可能性,
|
||||
* 写代码时始终只需要关注当前所有者的行为即可。
|
||||
*/
|
||||
}
|
||||
|
||||
fn ownership3(){
|
||||
/* 所有权不仅可以移交给变量也可以通过函数参数移交给函数,但是移交给函数有一个使用上的问题:
|
||||
* 移交给函数后,还需要函数通过函数返回值将所有权返回,不然变量的生命周期会随着调用的函数结束而结束
|
||||
*/
|
||||
let mut str1 = String::new();
|
||||
str1.push_str("This is a string");// 通过str1操作字符串,添加一串字符串到String里
|
||||
|
||||
/* opt1: 如下的操作是不被允许的,因为str1 所有权移交给了function join_str,str1已经不可再访问 */
|
||||
//join_str(str1, "sub string");
|
||||
//println!("after join str is {}", str1);
|
||||
/* opt2: 只有像如下的操作将所有权从functon的返回值中再次移交回来给到一个新的变量str1才可访问字符串
|
||||
* 注意这里的str1已经和上面的str1不一样了哦,上面那个str1已经被shadow掉了
|
||||
*/
|
||||
let (sub_len, str1) = join_str(str1, "sub string");
|
||||
println!("after join str is {}", str1);
|
||||
}
|
||||
fn join_str(mut str_src:String, sub_str:&str) -> (usize, String){
|
||||
let len = sub_str.len();
|
||||
str_src.push_str(sub_str);
|
||||
(len,str_src)
|
||||
}
|
||||
|
||||
fn ownership4(){
|
||||
|
||||
/* 像ownership3 所示的例子中的用法会使得复杂的数据类型在使用上会变得很麻烦,
|
||||
* 因为如果一个函数有多个参数并且每个参数都是复杂的数据类型,那么势必会导致
|
||||
* 每个函数的返回值都特别冗余,并且有时候我们所调用的函数只是用一下参数的一些值,并不会改变参数,
|
||||
* 也就是不是要所有权而是只是想使用一下。
|
||||
* 所以rust就有了引用和借用的概念:
|
||||
* 将变量借用给函数或另外一个变量使用。对于原变量就是借用,对于新的变量或者函数就是引用。
|
||||
* */
|
||||
let mut str1 = String::new();
|
||||
str1.push_str("This is a string");// 通过str1操作字符串,添加一串字符串到String里
|
||||
let sub_str = 'A';
|
||||
// 通过 & 将变量借用给has_char
|
||||
let ret = has_char(&str1, sub_str);
|
||||
match ret {
|
||||
//将字符串借用给函数has_char后str1依然用拥有其所有权,依然可以读写访问
|
||||
true =>println!("{} has char {}", str1, sub_str),
|
||||
false =>println!("[{}] has no char [{}]", str1, sub_str),
|
||||
}
|
||||
str1.push_str("add string after borrow");
|
||||
|
||||
/* 可以有多个不可变引用
|
||||
* 引用的变量是不可以修改其内容的,因为借你,你要原样的归还,也就是只能读不能写
|
||||
* 这就天然形成了读写锁
|
||||
*/
|
||||
let str2 = &str1;
|
||||
let str3 = &str1;// 可以有多个不可变引用
|
||||
//str2.push_str("cant add str!"); //❎
|
||||
println!("{} {} {}", str1, str2, str3);//尝试使用他们
|
||||
|
||||
/* 不可以同时有可变引用和不可变应用:
|
||||
* 只能分时复用,不能在同一块代码逻辑里
|
||||
* 我的理解是可变引用和不可变引用,相当于是指向原始变量的指针,当我们通过两个指针(一读一写)去访问原始字串时会导致数据竞争
|
||||
* 所以为了保证数据的一致性,不允许可能发生的同时读写的情况。
|
||||
*/
|
||||
let mut str1 = String::new();
|
||||
str1.push_str("This is a string");// 通过str1操作字符串,添加一串字符串到String里
|
||||
//let str2 = & mut str1;
|
||||
//str2.push_str("add string by borrowed mut str2");
|
||||
//let str3 = &str1; //这里会报错不能同时借用给muteable和immuteable。
|
||||
//println!("{} {} {}", str1, str2, str3); //在这里尝试使用三个字符串。
|
||||
//{
|
||||
// let str3 = &str1;
|
||||
// println!("{} {}", str1, str3); //在这里尝试使用
|
||||
//}
|
||||
{
|
||||
let str2 = & mut str1;
|
||||
str2.push_str("add string by borrowed mut str2");
|
||||
//str1.push_str("adas");// 不能同时读写
|
||||
//println!("{} {}", str1, str2); //在这里尝试使用。
|
||||
}
|
||||
}
|
||||
fn has_char(str_src:&String, sub_str:char) -> bool{
|
||||
let idx = str_src.find(sub_str);
|
||||
if idx == None{
|
||||
false
|
||||
}else{
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn ownership5(){
|
||||
//
|
||||
let mut str1 = String::new();
|
||||
str1.push_str("This is a string");// 通过str1操作字符串,添加一串字符串到String里
|
||||
let str2 = &str1;
|
||||
str1.push_str("add another string");
|
||||
|
||||
}
|
Reference in New Issue
Block a user