1、描述
打印聖誕頌歌 “The Twelve Days of Christmas” 的歌詞,並利用歌曲中的重複部分
2、代碼
fn main() {
let order_day = ["first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth"];
let mut present = "A partridge in a pear tree.".to_string();
for i in 0..12{
if i == 1{
present = "Two turtle doves, And ".to_string() + &present;
}else if i == 2 {
present = " Three French hens, ".to_string() + &present
}else if i == 3{
present = "Four calling birds, ".to_string() + &present
}else if i == 4{
present = "Five golden rings, ".to_string() + &present
}else if i == 5{
present = "Six geese a-laying, ".to_string() + &present
}else if i == 6{
present = "Seven swans a-swimming, ".to_string() + &present
}else if i == 7{
present = "Eight maids a-milking, ".to_string() + &present
}else if i == 8{
present = "Nine ladies dancing, ".to_string() + &present
}else if i == 9{
present = "Ten lords a-leaping, ".to_string() + &present
}else if i == 10{
present = "Eleven pipers piping, ".to_string() + &present
}else{
present = "Twelve drummers drumming, ".to_string() + &present
}
print!("On the {} day of Christmas, my true love sent to me:{}\n", order_day[i], present);
}
}
運行結果:
關鍵點:
- 字符串拼接
3、總結
&str與string的區別
什麼是&str,什麼是String
- &str
{
let s ="hello";
//變量s綁定到了一個字符串字面值,這個字符串值是硬編碼進程序代碼中的。這個變量從聲明的點開始直到當前作用域結束時都是有效的
println!("{}", s)
} //變量存儲在棧上並且當離開作用域時被移出棧[就是s變量名不再和這個棧空間綁定了]
作用域是一個項在程序中有效的範圍。
- string
let s = String::from("hello");
String由3部分組成,一個指向存放字符串內容內存的指針,一個長度,一個容量。這一組數據存放在棧上。右側是堆上存放內容的內存部分
長度表示String的內容當前使用了多少字節的內存。容量是String從操作系統總共獲取了多少字節的內存。
s1是一個堆上內存的引用。
$str不可變
fn main(){
let x = "hello"; //作用域:從聲明的點開始直到下一個x重新定義結束
//x = " xdwe"; //error
let x = "world"; //覆蓋,重新生成了一個x變量
}
- "hello"是一個字符串字面量, x的類型是&str。x存儲在棧上,當x離開作用域時就會由所有權系統從棧上移除【這和其他語言不一樣】
- &str可以看成一個固定大小固定內容的數組,不能拼接,不能更改;
- 程序編譯成二進制文件之後,這個字符串會被保存在文件內部,所以s是特定位置字符串的引用&str
- &str由於保存在二進制文件內,所以&str類型不存在生命週期的概念,它是整個程序生命週期static內都能訪問的
爲什麼String是可變的
1、字符串字面值在編譯時就知道其內容,所以文本被直接硬編碼進最終的可執行文件中。因此字符串字面值是不可變的。
但是我們不能爲了一個在編譯時大小未知並且的文本而將一塊內存放入二進制文本中,並且文本大小還可能隨着程序運行而改變:而堆內存的大小可以動態變化,String就是存儲在堆上的
2、對於String類型,爲了支持一個可變、可增長的文本字段,需要在堆上分配一塊在編譯時未知大小的內存來存放內容。這意味着:
- 必須在運行時向操作系統請求內存
- 需要一個當我們處理完String時將內存返回給操作系統的方法
第一部分由程序員完成:當調用String::from時,它的實現請求其所需的內存
第二部分由編程語言完成:
- 在垃圾回收GC語言中,GC記錄並清除不再使用的內存;
- 在沒有GC的語言中,程序員手動釋放,且需要精確的爲一個 allocate 配對一個 free;
- 對於Rust而言,內存在擁有它的變量離開作用域之後就被自動釋放
fn main() {
let mut s = String::from("hello"); //作用域:從聲明的點開始直到下一個}結束
s.push_str(", world!"); //s是可以改變的
println!("{}", s);
}
當可變變量s離開作用域的時候,也就是結尾的}處,Rust自動調用drop函數將內存返回給操作系統
字符串拼接
3、String + n個&str,但是&str不能添加String
fn main() {
//&str =>String
let s1 = "hello ".to_string(); //方法一
let s2 = String::from(" world"); //方法二
let s3 = "!";
let s = s1 + &s2 + s3; //String,後面可以接N個&str.
println!("{}", s);
}
不太理解
Rust官方的解釋:
String是一個被擁有的在堆上分配的UTF-8的字節緩衝區。可變String可以被修改,根據需要增加其內容
&str是一個指向分配在某處的String的一個固定容量的[視圖]。如果切片是在從String解引而來的,則通常是指向在堆上,如果是字符串字面值,則指向靜態內存
&str是一個由Rust語言實現的原生類型,而String則是由標準庫實現的。
對於Rust而言,"字符串"是Unicode標量值的序列編碼爲utf-8字節的流。所有字符串必須保證爲有效的utf-8編碼序列
參考:https://kaisery.github.io/trpl-zh-cn/ch04-01-what-is-ownership.html