? ? 所有權(quán)轉(zhuǎn)移,Rust中沒有垃圾收集器,使用所有權(quán)規(guī)則確保內(nèi)存安全,所有權(quán)規(guī)則如下:
? ? 1、每個值在Rust中都有一個被稱為其所有者(owner)的變量,值在任何時候只能有一個所有者。
? ? 2、當(dāng)所有者離開作用域,這個值將被丟棄。
? ? 3、所有權(quán)的轉(zhuǎn)移時零成本的,這里不需要對新的變量開辟一塊內(nèi)存用于存儲數(shù)據(jù)。新變量只是重新分配了資源的所有權(quán)。
? ? 例子1:所有權(quán)傳遞(變量)
fn main()
{
let x="hello".to_string();//"hello"的所有者為x
let y=x;//"hello"的所有者變?yōu)閥,這個時候原來的所有者x已失效
println!("{}",x);//
}
例子2:所有權(quán)傳遞(函數(shù))
fn create_string() ->String
{
// 創(chuàng)建并返回一個新的String
String::from("Hell,ownership!")
}
fn transfer_ownership(s:String) -> String
{
//返回輸入的String,轉(zhuǎn)移所有權(quán)
s
}
fn main() {
//create_string函數(shù)創(chuàng)建了一個值"Hell,ownership!",并將所有權(quán)傳遞給了my_string。
let my_string=create_string();
//my_string將值"Hell,ownership!"的所有權(quán)傳遞給了函數(shù)transfer_ownership,函數(shù)又將所有權(quán)傳遞給了transferred_string
let transferred_string=transfer_ownership(my_string);
//此時my_string已不再對值"Hell,ownership!"擁有所有權(quán)。
println!("my_string string: {}", my_string);
// 此時transferred_string對值"Hell,ownership!"擁有所有權(quán)。
println!("Transferred string: {}", transferred_string);
}
? ? 克?。?/p>
? ? 1、當(dāng)克隆一個變量時,相當(dāng)于創(chuàng)建了數(shù)據(jù)的一個完整副本。
? ? 2、與所有權(quán)轉(zhuǎn)移相比,克隆的成本較大,因為涉及到了要內(nèi)存的使用和數(shù)據(jù)的復(fù)制。
? ? 3、所有權(quán)轉(zhuǎn)移后原始變量失效,克隆之后原始變量仍然有效,并且原始變量保留了數(shù)據(jù)的所有權(quán)。這里需要注意,克隆后,兩個變量是完全獨(dú)立的數(shù)據(jù)實例。
? ? 例子3:
fn main()
{
let x="Hello".to_string();//x獲取了"Hello"的所有權(quán)
let y=x.clone();//傳遞x的副本給y
clone_ownership(y);//傳遞x的副本y給函數(shù)clone_ownership
//x依然對"Hello"擁有所有權(quán)
println!("x String:{}",x);
//y對"Hello"還擁有所有權(quán)嗎?不再擁有所有權(quán)了,因為已經(jīng)將所有權(quán)傳遞給了函數(shù)clone_ownership
// println!("y String:{}",y);
}
fn clone_ownership(s:String)
{
println!("{}",s);
}
? ? 引用:
? ? 1、引用有可變引用(&mut T)和不可變引用(&T)。
? ? 2、可變引用允許修改引用所指向的值,而不可變引用不允許修改引用所指向的值。
? ? 3、為了防止數(shù)據(jù)競爭,Rust中在任何時間,只能擁有一個可變引用到特定的數(shù)據(jù)。
? ? 4、由于不可變引用不會改變數(shù)據(jù),Rust中可以擁有任意數(shù)量的不可變引用。
? ? ?例子4:
// 定義一個函數(shù),它接受一個整數(shù)的不可變引用
fn print_int(value:&i32)
{
// 打印出傳入整數(shù)的值
println!("The value is: {}",value);
}
fn main()
{
let _int=11;
// 調(diào)用函數(shù),傳入整數(shù)的不可變引用
print_int(&_int);
}
? ? 例子5:
// 定義一個函數(shù),它接受一個整數(shù)的可變引用
fn print_int(value:&mut i32)
{
// 將整數(shù)的值加倍
*value *=10;
}
fn main()
{
let mut _int=10;
// 調(diào)用函數(shù),傳入整數(shù)的可變引用
print_int(&mut _int);
// 打印加倍后的整數(shù)值
println!("The value is :{}",_int);
}
5、生命周期參數(shù),它可以告訴編輯器,參數(shù)的引用和返回值的引用都具有相同的生命周期。例子6中的'a就是生命周期參數(shù)
?文章來源地址http://www.zghlxwxcb.cn/news/detail-808594.html
例子6
fn return_reference<'a>(data:&'a String)->&'a String
{
data //返回的引用與輸入的引用具有相同的生命周期
}
fn main()
{
let external_string=String::from("Hello world");
let string_ref=return_reference(&external_string);
println!("{}",string_ref);// 這是安全的,因為external_string的生命周期貫穿了整個main函數(shù)
}
例子7
//定義一個包含引用的結(jié)構(gòu)體,需要生命周期注解
struct Item<'a>
{
//'a表示引用的生命周期
name:&'a str,
}
// 實現(xiàn)結(jié)構(gòu)體,戰(zhàn)術(shù)如何使用生命周期
impl<'a> Item<'a>
{
// 創(chuàng)建一個新的Item實例,返回一個帶有生命周期的實例
fn new(name:&'a str)->Self{
Item {name}
}
}
fn main()
{
let name =String::from("Rust Programming");// 創(chuàng)建一個String類型的變量
let item= Item::new(&name);//借用name的引用來創(chuàng)建Item實例
println!("Item name:{}",item.name);//打印Item中的name字段
}//name的生命周期結(jié)束,item.name的引用也不再有效
例子8
fn print_shorter(r:&str)
{
println!("The string is:{}",r);
}
fn main(){
let long_lived_string=String::from("This is a long-lived string.");
{
let short_lived_str:&str=&long_lived_string;//創(chuàng)建一個常生命周期的引用
// 下面的函數(shù)調(diào)用中,short_lived_str的生命周期會被強(qiáng)制縮短以匹配print_shorter
print_shorter(short_lived_str);
}//short_lived_str的生命周期結(jié)束
//這里long_lived_string仍然有效,因此上面的強(qiáng)制轉(zhuǎn)換是安全的
println!("{}",long_lived_string);
}
例子9
fn main()
{
let mut data=vec![1,2,3,4,5];
//創(chuàng)建一個不可變引用
let data_ref=&data;
//打印使用不可變引用的數(shù)據(jù)
println!("Values via immutable reference:{:?}",data_ref);
// 下面嘗試創(chuàng)建一個可變引用將會失敗,因為`data`已經(jīng)被不可變引用借用
let data_mut_ref = &mut data;
println!("{}", data_mut_ref);// 這行會導(dǎo)致編譯錯誤,編譯錯誤如下圖
//下面嘗試創(chuàng)建一個可變引用將不會失敗
// let data_mut_ref=&mut data;
// println!("{:?}",data_mut_ref);
//只有當(dāng)不可變引用不再使用后,才能創(chuàng)建可變引用
//這里不再使用不可變引用data_ref,因此可以創(chuàng)建可變引用
// let data_mut_ref=&mut data;
// data_mut_ref.push(6);
// println!("Values after mutation:{:?}",data_mut_ref);
}
從錯誤截圖上看,只有使用{:?}編譯器錯誤就不存在了。
例子10:如果有一個或多個不可變引用&T,那么在同一作用域內(nèi)不能有可變引用&mut T。
如果有一個可變引用&mut T,那么在同一作用域內(nèi)不能有其他的可變引用或不可變引用&T。
編譯器報錯提示如下
struct MyStruct{
value:i32,
}
//這個函數(shù)嘗試同時接受一個對象的可變和不可變引用
fn example_fn(mutable_ref:&mut MyStruct,immutable_ref:&MyStruct){
println!("Mutable reference value:{}",mutable_ref.value);
println!("Immutable reference value:{}",immutable_ref);
}
fn main() {
let mut my_object=MyStruct{value:10};
//嘗試同時借用可變引用和不可變引用
example_fn(&mut my_object, &my_object);
}
?文章來源:http://www.zghlxwxcb.cn/news/detail-808594.html
?
例子11:
fn main()
{
let x=10;//定義一個整數(shù)變量x
let y=&x;//創(chuàng)建一個指向x的引用y
println!("The value of x is:{}",x);//直接打印變量x的值。
println!("The address of x is:{:p}",y);//打印引用y的地址,使用{:p}格式化指針地址
println!("The value of y is:{}",y);//打印應(yīng)用y的值,這里會打印出地址 注意這里打印出來的是10而不是地址,不確定是不是Rust版本的問題。
println!("The value pointed to by is :{}",*y);//使用解引用操作符來打印y指向的值
}
例子12
// 定義一個包含字符串引用的結(jié)構(gòu)體Book
struct Book<'a>{
//'a是一個生命周期注解,表示title的生命周期
title:&'a str,
}
fn main(){
let title=String::from("The Rust Programming Language");
let book=Book{
//title 是一個字符串切片,他引用了title變量的數(shù)據(jù)
title:&title,
};
println!("Book title:{}",book.title);
}
例子13
// longset 函數(shù)定義了一個生命周期參數(shù)'a,這個生命周期參數(shù)制定了輸入?yún)?shù)和返回值的生命周期必須相同。
fn longset<'a>(x:&'a str,y:&'a str)->&'a str
{
if x.len()>y.len(){
x// 如果x的長度大于y,返回x
}
else {
y //否則,返回y
}
}
fn main()
{
let string1=String::from("Rust");
let string2=String::from("C++");
let result=longset(string1.as_str(), string2.as_str());//longset函數(shù)比較兩個字符串切片的長度
println!("The longeset string is {}",result);
//注意 result 的生命周期與string1和string2的生命周期相關(guān),因此它們必須在result被使用之前保持有效
}
例子14
// 定義一個結(jié)構(gòu)體ImportantExcerpt,它包含一個字符串切片字段part
struct ImportantExcerpt<'a>
{
part:&'a str,
}
fn main()
{
let novel=String::from("Call me ishmael. Some years ago ...");
let first_sentence=novel.split('.').next().expect("Could not find a '.'");
let excerpt=ImportantExcerpt{
part:first_sentence,
};
//打印出結(jié)構(gòu)體中的字符串切片
println!("Important excerpt:{}",excerpt.part);
}
例子15
// 定義一個結(jié)構(gòu)體ImportantExcerpt,它包含一個字符串切片字段part
struct ImportantExcerpt<'a>
{
part:&'a str,
}
//為ImportantExcept結(jié)構(gòu)體實現(xiàn)方法
impl <'a> ImportantExcerpt<'a> {
fn announce_and_return_part(&self,announcement:&str)->&str{
println!("Attention please:{}",announcement);
self.part
}
}
fn main()
{
let novel=String::from("Call me ishmael. Some years ago ...");
let first_sentence=novel.split('.').next().expect("Could not find a '.'");
let excerpt=ImportantExcerpt{
part:first_sentence,
};
let announcement="I'm going to tell you something important!";
let part=excerpt.announce_and_return_part(announcement);
//打印出結(jié)構(gòu)體中的字符串切片
println!("Important excerpt:{}",part);
}
例子16
//定義一個擁有靜態(tài)生命周期的字符串常量
static MESSAGE:&'static str="Hello,this is a static lifetime example";
fn main()
{
//打印這個靜態(tài)生命周期的字符串
println!("{}",MESSAGE);
}
例子17
//定義一個函數(shù),該函數(shù)接收兩個引用參數(shù):一個是不帶生命周期的引用,另一個是帶生命周期的'a的引用
fn select<'a>(first:&i32,second:&'a i32)->&'a i32{
//這里我們簡單地返回第二個參數(shù),它帶有生命周期'a
second
}
fn main()
{
let num1=10;
let num2=20;
//創(chuàng)建一個生命周期較長的引用
let result;
{
let num3=num2;
//調(diào)用函數(shù),num1的引用不帶生命周期,num3的引用帶有生命周期
result=select(&num1, &num3);
}//num3的生命周期結(jié)束
//打印結(jié)果,result引用的是num2,因為它與num3共享相同的數(shù)據(jù)
println!("The selected number is {}",result);
}
例子18
//定義一個結(jié)構(gòu)體Book,包含一個字符串切片引用,代碼書名
struct Book<'a>{
name:&'a str,
}
//實現(xiàn)Book結(jié)構(gòu)體的一個方法get_name,返回書名的引用
//這里沒有顯示標(biāo)注生命周期,因為編譯器會自動應(yīng)用生命周期省略規(guī)則
impl<'a> Book<'a>
{
//根據(jù)省略規(guī)則,這里的返回值生命周期被自動推導(dǎo)問為與&self相同
fn get_name(&self)->&str{
self.name
}
}
fn main()
{
let book=Book{name:"The Rust Programming Language"};
//調(diào)用get_name方法,打印返回的書名引用
println!("Book name:{}",book.get_name());
}
例子19
// 定義一個泛型函數(shù)`slice_first`,它有一個泛型類型`T`和生命周期`'a`
fn slice_first<'a, T>(data: &'a [T]) -> Option<&'a T> {
// 使用`.get()`方法來嘗試獲取slice的第一個元素的引用
// 如果存在,則返回Some(&T),否則返回None
data.get(0)
}
fn main() {
// 創(chuàng)建一個整數(shù)類型的slice
let numbers = vec![1, 2, 3, 4, 5];
// 調(diào)用`slice_first`函數(shù),并打印返回的結(jié)果
if let Some(first) = slice_first(&numbers) {
println!("The first number is {}", first);
} else {
println!("The slice is empty.");
}
// 創(chuàng)建一個字符類型的slice
let letters = vec!['a', 'b', 'c', 'd', 'e'];
// 同樣調(diào)用`slice_first`函數(shù),并打印返回的結(jié)果
if let Some(first) = slice_first(&letters) {
println!("The first letter is {}", first);
} else {
println!("The slice is empty.");
}
}
到了這里,關(guān)于Rust基礎(chǔ)語法1的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!