本文內容摘自<<The rust programming language>>,作者:美國的steve klabnik ,Carol nichols。
中國工信出版社2020年出版,但在國外據說是2018年出版的。
關於本人的入門大部分來自此書。
不過此書由於出版的時間較早(假定是2018),那麼那個時候的rustc的版本是1.30左右,所以在1.81的環境上還是具有不少的出入。
需要在完成本書的基本學習之後,再研究1.81上的內容.
本文的目的在於作為一個筆記,讀者可以作為參考,也可以翻閱任意部落格或者網站上的。
一、概述
在作者的這個章節中,簡單介紹了基本概念:
- 變數與可變性
- 資料型別
- 資料型別-標量型別
- 資料型別-複合型別
rust的資料型別遠不止這些!
1.1、名稱風格_蛇形
rust推薦用蛇形風格,這和java,c++之類的不同。
我個人認為蛇形還是比較人性化的,一方面提升了輸入速度,其次可能還更好閱讀。
不過這個風格並非是強制的,但是rustc會多管閒事,在編譯的時候給出不少警告。
二、變數與可變性
這個變數的最重要概念之一,強調幾點:
1.變數具有可變和不可變屬性,和其它語言一樣。但是rust預設是不可變
2.編輯器可以保證不能修改不可變變數,這是重點
其它語言也有這種情況,不過沒有那麼突出。其它語言中預設是可變的,而rust是預設可變的
例如在JAVA中
int a=10; final int b=20; //不可變需要顯示定義 a=99; b=29; //這個會編譯錯誤
而rust是翻過來的:
let score=100; //預設不可變 score=91; //這個會編譯報錯 let mut age=90; //要可變,需要顯示申明 age=99;
三、資料型別
原文只強調了一點:rust是靜態型別語言,所以在編譯的時候就需要知道所有變數的具體型別.
這就是靜態型別語言的特點,好處是避免潛在的錯誤,嚴謹的語言一般都支援這個。
不嚴謹的,也搞了一些手段避免過於散漫導致的問題,例如js。用const,let來避免可能的問題。
python也是動態型別的。
c,C++,java也是靜態型別語言.
四、資料型別-標量型別
所謂標量,即該型別主要是為了表示某種”量"。
在本文中,範圍很狹窄,就是數量。
所以有以下幾個標量型別:整數、浮點數(小數)、布林、字元
注意,最後一個是字元,不是字串.
有符號整數- i8/16/32/64/size ,分別表示8位,16位,32位,64位和平臺架構型別
無符號整數-u8/16/32/64/size ,分別表示8位,16位,32位,64位和平臺架構型別
浮點-f32,f64-rust預設推到字面量位f64,這是因為現代cpu更快,且f64提供更高的精度
字元(char)-但是它佔據四個位元組,是unicode,意味著可以展示各種語言的字元和一些表情包
注意,所謂平臺架構型別usize,isize,它們和作業系統cpu架構有關。如果是64位的,則是64,否則就是32.暫時沒有128之類的。
示例:
fn main(){ //1.0 整數 let my_age: u8=90; // 0~255 //let f_age:u8=300; //溢位報錯 let my_food_amount: u16=50000; // 0~65535 let ys=my_food_amount%9; let my_cells: u32= 1000000000; //0~4294967295 ,即0到42億 let star_qty: u64 = 9000000000000; //0~18,446,744,073,709,551,615 即0~1844兆 let max:u128 =9292; println!("my_age={},my_food_amount={},my_cells={},star_qty={},", my_age,my_food_amount,my_cells,star_qty); // my_age=99; // 預設不可變,這樣會爆編譯錯誤 //2.0 浮點數,浮點數運算是否存在精度丟失問題? let score:f32=90.4; //-3.4 X 10³⁸-3.4 X 10³⁸ let money:f64=3.1415926532758; //-1.8 X 10³⁰⁸ - 1.8 X 10³⁰⁸ //3.0 布林 ,佔據一個位元組 let is_ok=true; let is_successful=false; //4.0 字元型別,非字串型別 let dog_tag:char='a'; //列印常見的120幾個ascii字母 let mut str:String=String::from(""); let mut code:u8=0; for i in 1..255 { let ch=code as char; str=str+&ch.to_string(); if (code%30==0){ println!("{}",str); str=String::from(""); } code += 1; } if (str!=""){ println!("{}",str); } //演示重複定義一個變數,這在java這樣的語言中是不允許的 let cat="小白"; println!("{}",cat ); // let cat=90; println!("{}",cat); //字面表達標量型別 let a1=10_i32; let a2=10.2_f32; let a3=10.554_f64; let a4=254u8; let a5=99.88_f32; println!("{},{},{},a4={},{}",a1,a2,a3,a4,a5); }
示例中除了展示定義、訪問型別,還增加了字面量表達型別的方法 .
在前例中,都是一些常見的,但我們也很感興趣如何表示不同進位制的數字(原文例子):
//字面量表達不同的整數 let d1=10; let d2=0o10; //8進位制 0o開頭 let d3=0x10; //16進位制 0x開頭 let d4=0b01001; //二進位制 0b開頭 println!("d1={},d2={},d3={},d4={}",d1,d2,d3,d4);
列印結果如下:
五、資料型別-複合型別
複合型別,故名思意:該型別的值通常由多個標量型別組成。
本文提到了以下幾個:
元組(tuple),用的名稱同python一樣. 不可變長,但元素個數型別可以不一樣.。有點型別java的Object[]
陣列,不可變長,要求成員型別必須一致,類似java的 int[],char[]之類的
用於複合型別的時候,rust的語法還頗有python的樣子,比較隨意(也有人認為方便)
示例:
fn main(){ //1.0 元組 tuple- 元素型別可以不同,個數不能變化 //定義方式常見有兩種:指定每個元素的型別,或者不指定 //總之這個tuple不知有啥用,訪問非常不方便,定義也非常靈活? 效能還是什麼? let i:u8=9; let my_nums=(0,1,2,3,4,5,6,7,8,99); let my_nums32:(u32,u32,u32,u32)=(1000,109393,29992,1992); //訪問元素的方式-使用點號加序號 println!("my_nums is:{}",my_nums.9); //匹配獲取,但用於巨長的,並不適合 let tuple = (1, "hello", 3.14); let (a, b, c) = tuple; println!("a: {}, b: {}, c: {}", a, b, c); //2.0 陣列 array - 元素型別必須一致,個數不能變化 //陣列的定義方式足夠靈活,訪問的方式也更靈活,更接近大部分程式語言,即可以透過索引下標訪問,索引從0開始 let score_arr=[10,20,30,40]; let food_arr=["大米","糙米","地瓜","包菜","白菜"]; for i in 0..food_arr.len() { println!("第{}個食物:{}",i+1,food_arr[i]); } //3.0 print_food(&food_arr); } fn print_food(foods:&[&str]){ for i in 0..foods.len() { println!("第{}個食物:{}",i+1,foods[i]); } }
注意,上例中print_food的引數如果定義為 foods:[&str]那麼會導致編譯錯誤:doesn't have a size known at compile-time