首先須要安裝Dart SDK(https://www.dart-china.org/t/...),SDK安裝完成呢後,選擇一款編輯工具。這裏就先只推薦兩款工具 VS Code ,Android Studio。工具下載完成後,安裝dart插件,這個時候就能夠編寫dart代碼了。咱們先新建一個hello.dart文件,而後在文件中輸入下方的代碼,點擊運行按鈕就能夠執行代碼。java
// 在dart中,main方法是代碼運行的入口方法,一切都是從main方法開始的。。 void main (){ // 點擊IDE運行按鈕 在打印臺中會打印出 hello Dart。 接下來的例子都是在該方法下執行的(除特殊說明)。 print('hello Dart'); }
String String能夠用 '' 或 "" 來建立,也可使用''' 或者"""來建立可變行的字符串。程序員
eg.num與String的一些經常使用操做算法
// String -> num int one = int.parse('1'); print(one + 2); // 輸出 3 double類型同理 int one = int.parse('hello'); print(one + 2); // 報錯 // int -> String String oneStr = 1.toString(); print(oneStr); // 輸出 1 // double -> String String oneStr = 3.1455.toStringAsFixed(2); print(oneStr); // 截取兩位小數, 輸出3.15 四捨五入 String twoStr = 3.toStringAsFixed(2); print(twoStr); // 輸出3.00 // 可使用${表達式}將表達式的值放入字符串中。若是表達式是標識符,{}可省略 String oneStr = 'hello'; String twoStr = "dart"; print('$oneStr $twoStr'); //輸出 hello dart print('$oneStr ${twoStr.toLowerCase()}'); //輸出 hello dart print('$oneStr $twoStr.toLowerCase()'); //輸出 hello dart.toLowerCase()
bool Dart是強bool類型檢查。api
if(非bool類型) 報錯,assert( 非bool類型)報錯,也就是說須要bool類型的,若是咱們用int 等非bool類型的值都會報錯。數組
if (1){} // 報錯
List 列表閉包
var list_1 = new List(); // 非固定長度 new能夠省略 // 添加元素 list_1.add('1'); // 添加多個元素 list_1.addAll(['1', '2']); // 獲取list長度 print(list_1.length); // 輸出2 // 獲取list最後一個元素 print(list_1.last); //輸出 2 // 獲取list第一個元素 print(list_1.first); // 輸出 1 // 查詢某位置的元素,index從0開始 print(list_1[0]); // 輸出 1 // 根據某個元素獲取對應的index print(list_1.indexOf("1")); // 輸出 0 // 刪除元素 list_1.removeAt(0); // 經過索引刪除 list_1.remove("1"); // 經過對象刪除 若是有兩個 "1" 那麼會刪除第一個 list_1.removeLast(); // 刪除最後一個元素 list_1.removeRange(start,end); // 刪除範圍內的數據 list_1.removeWhere((item) => item.length > 6);// 刪除元素長度大於6的元素 這種寫法可見下面箭頭函數的詳解 list_1.clear(); // 清除全部元素 /*注意*/ List list_2 = new List(2); // 固定長度 list_2.add('1'); // 報錯 報錯信息 Cannot add to a fixed-length list // 另一種定義方式 List list_3 = ['1','2','3']; print(list_3); // 輸出 [1,2,3]
Set 集合 Set是沒有順序且不能重複的集合,因此不能經過索引去獲取值ide
Set set_1 = new Set(); Set set_2 = new Set(2); // 報錯 set沒有固定長度的定義 set_1.add('1'); set_1.add('2'); set_1.add('1'); print(set_1); // 輸出 {1, 2} // 能夠和list同樣經過contains來判斷是否包含某個元素 print(set_1.contains("1")); // 輸出 true set_1.addAll(['b','c']); print(set_1); // 輸出 {1, 2, b, c}
Map 映射是無序的鍵值對。鍵和值均可以是任何類型的對象。函數
// 經常使用的兩種定義方式 Map map_1 = Map(); Map map_2 = {"key_1":"value_1","key_2":"value_2"}; print(map_1); // 輸出 {} print(map_2); // 輸出 {key_1: value_1, key_2: value_2} // 賦值 map_1["1"] = "one"; map_1["2"] = "two"; print(map_1); // 輸出 {1: one, 2: two} map_1["1"] = "first"; print(map_1); // 輸出 {1: first, 2: two} map_1[1] = "one"; // 在map中key必需要保持惟一 value能夠相同 key類型能夠爲任意其餘類型 print(map_1); // 輸出 {1: one, 2: two, 1: one} // 經常使用api map_1.remove(1); // 刪除key爲1的元素 map_1.containsKey(1); // 判斷是否存在key爲1的元素
內置函數/方法工具
print("hello Dart");
這個是經常使用的將數據打印到控制檯的方法,這是系統提供給咱們的內置函數,能夠直接調用。學習
自定義方法
自定義方法的基本格式:
返回類型 方法名稱 (參數1,參數2,...){
方法體
return 返回值;
}
int getMaxCount(int a, int b){ if (a > b){ return a; } return b; } print(getMaxCount(2, 1)); // 輸出 2 // 在dart中 返回值和參數類型是能夠省略的 getMinCount(a,b){ if (a < b){ return a; } return b; } print(getMinCount(2, 1)); // 輸出 1
方法的傳參
// 可選參數 String printUserInfo(String username,[int age]){ // username和age表示是形參 其中age表示可選參數 return "姓名:$username 年齡:$age"; } print(printUserInfo("張三",30)); // 張三 和 30 表示實參 print(printUserInfo("張三")); // 這裏能夠不用傳入age的參數,若是age不是可選參數的話,那麼age是必需要傳的 // 默認參數 String printUserInfoDefalut(String username,[int age,String sex = "男"]){ return "姓名:$username 年齡:$age 性別:$sex"; } print(printUserInfoDefalut("李四",30)); // 輸出 姓名:李四 年齡:30 性別:男 /*注意 對於可選參數的傳遞是按照參數的順序進行的 print(printUserInfoDefalut("李四","女")); 這裏會報錯。雖然sex和age都是可選參數,可是當對一個形參賦值時,會默認選擇第一個。這裏可選參數的第一個形參是age int類型的,這裏傳遞一個"女"是string類型的,因此會報錯。 */ // 命名參數 String printUserInfoName(String username,{int age,String sex = "男"}){ return "姓名:$username 年齡:$age 性別:$sex"; } print(printUserInfoDefalut("李四",age:30,sex:"男")); // 輸出 姓名:李四 年齡:30 性別:男 // 這樣咱們經過指定參數名稱實現咱們想要傳遞的參數。這個比較經常使用。 // 將方法做爲參數 fun_1(){ print("方法1"); } fun_2 (Function fun){ // fun方法其實就是一個Function對象 fun(); } fun_2(fun_1); // 輸出 方法1
箭頭函數
// 遍歷數組 List list = ["h","e","l","l","0"]; // 正常寫法 list.forEach((element){ print(element); }); // 箭頭函數的方式 箭頭後跟的方法體只能是一行 這只是一種簡寫的方式 list.forEach((element)=>print(element)); list.forEach((element) => { print(element) // 這裏不能寫分號,也是隻能執行一行代碼 }); List list_1 = [1,3,5,1,3,7]; // 這也是數組的一種遍歷並處理的方式 List list_2 = list_1.map((element){ if(element >3){ return element*3; } return element; }).toList(); print(list_2); List list_3 = list_1.map((element)=>element>3?element*3:element).toList(); print(list_3);
自執行與自調用
//實際上自執行方法咱們能夠理解爲一個匿名函數的自調用 ((){})();// 格式 將一個匿名函數用()包起來 而後執行 ((int n){ print(n); })(12); //輸出12 // 方法能夠本身調用本身 int sum = 1; fn(n){ sum*=n; if (n == 1){ return; } fn(n-1); } fn(5); // 這樣經過方法的自調用能夠實現5的階乘
閉包
閉包:常駐內存,不會污染全局。寫法:函數嵌套函數,並return內層函數。
//閉包 fun(){ // 雖然這裏定義的是一個局部變量,可是經過閉包的寫法就不會被垃圾回收機制回收,且不會污染全局 int a = 1; return (){ a++; print(a); }; } Function b = fun(); // 由於fun方法返回的就是一個方法,因此下面直接調用b方法。 b(); b(); b(); // 輸出 2 3 4
Dart中一切皆對象,都是繼承自Object類。因此在Dart中不存在基本數據類型,咱們定義的任何一個對象,若是不將其賦值的話,那麼這個對象就是一個null對象。
int a; int b = 0; print(a); // 輸出 null print(b); // 輸出 0
Dart是動態型語言,若是沒有指定其類型時,則默認時dynamic類型。在運行時會自動推導出具體的類型。
var str = 'shsh'; str = 1; // 報錯
運算符及修飾符
const:與final有一點相似,即只能被賦值一次。可是其修飾的對象有必定的限制。const修飾的對象的狀態是徹底能夠在編譯期間就能肯定的,而且是不可變的。
const n = 1+2;// 可行 由於這個是在編譯期間咱們就知道n = 3的 const list = new List(); // 不可行 const list_1 = [1,2,3]; // 可行 list_1 = [3,4]; // 不可行
經常使用的運算符和表達式
//加減乘除 int a = 10; int b = 3; print(a/b); // 3.3333333333333335 不用判斷除數和被除數的類型,默認返回double類型 print(a~/b); // 3 整除取整 print(a*b); // 30 print(a+b); // 13 print(a-b); // 7 print(a%b); // 1 取餘 //as 定型 Person per = new Person(); // 咱們定義一個Person類,關於類的定義下文會介紹 // 若是per是Person類型的話 那麼就給Person的name屬性賦值,若是不是Person類型則不賦值 並 (per as Person).name = "張三"; // is 若是對象是指定的類型 那麼就返回true 不然就返回false if (per is Person){ per.name = "張三"; } /// 注意:以上代碼不相等。若是per爲空或不爲Person,第二個示例(帶is)什麼也不作;第一個(帶有as)拋出異常。 // ??與三目運算符 String str_1; String str_2 = "張三"; print(str_1??str_2); // 輸出 張三 print((str_1 is! Null)?str_1:str_2); // 輸出張三 在dart中 關於條件的判斷必須是bool類型 // 級聯符號 能夠避免建立臨時變量的繁瑣步驟 Person() ..name ="張三"; // 等價於 Person per = new Person(); per.name = "張三"; // ?. 有條件的成員屬性訪問 Person per; // 這裏per就是null // 若是直接調用成員會報錯 per.name = "張三"; // 報錯 per?.name = "張三"; // 不會報錯
類的建立
// 與上面的例子不一樣,類的定義須要與mian方法同級 class Person{ String name; // 屬性 void study (){ print("學習"); } // 方法 } void main (){ // 實例化,也就是建立對象 Person per = new Person(); // per就是一個對象 per.name = "張三"; print("${per.name}"); // 輸出 張三 調用對象的屬性 per.study(); // 輸出 學習 調用方法 }
類的構造函數
默認構造函數。每一個類都有一個默認的構造函數,默認是不用寫的,若是須要在構造函數作操做的話,則重寫一下默認構造函數。
class Person{ String name; //構造參數名與類名要相同 Person(){ // 無參 print("我須要在這裏作一些操做"); } // 初始化列表 person():name = "張三"{ // 在執行構造函數運行以前 初始化一些實例變量 } } class Student{ String name; Student(String name){ // 有參數 參數必傳 this.name = name; } void printStudentInfo (){ print("學生的姓名:${this.name}"); } } class Coder{ String name; Coder(this.name); // 簡寫的有參構造函數 參數必傳 void printCoderInfo (){ print("程序員的姓名:${this.name}"); } } class Engineer{ String name; Engineer({this.name}); // 簡寫的有參構造函數 參數非必傳 void printEngineerInfo (){ print("工程師的姓名:${this.name}"); } } void main (){ // 實例化,也就是建立對象 Person per = new Person(); // 輸出 我須要在這裏作一些操做。 // 報錯 由於咱們修改了默認的構造函數,因此以前的無參構造函數就不能使用了。 // Student stu = new Student(); Student stu_1 = new Student('張三'); stu_1.printStudentInfo(); Coder coder = Coder("張三"); coder.printCoderInfo(); Engineer eng = new Engineer(); eng.printEngineerInfo(); // 輸出 工程師的姓名:null Engineer eng_1 = new Engineer(name: "張三"); eng_1.printEngineerInfo(); // 輸出 工程師的姓名:張三 }
命名構造函數。類是能夠有多個構造函數的,經過不一樣的命名來實現不一樣功能的構造函數
class Engineer{ String name; String hairStyle; //髮型 Engineer({this.name,this.hairStyle = "茂密的頭髮"}); // 簡寫的有參構造函數 參數非必傳 Engineer.seniorEngineer(String name){ //命名構造函數 this.name = name; this.hairStyle = "禿了"; } void printEngineerInfo (){ print("工程師的姓名:${this.name} 髮型:${this.hairStyle}"); } } void main (){ Engineer eng_1 = Engineer(name:"張三"); eng_1.printEngineerInfo(); Engineer eng_2 = Engineer.seniorEngineer("李四"); eng_2.printEngineerInfo(); }
類中的setter和getter方法
class Rect{ num height; num width; Rect(this.height,this.width); // getter方法 get area{ return this.height*this.width; } // setter方法 set areaHeight(num height){ this.height = height; } } void main(){ Rect re = Rect(10,10); print("面積:${re.area}"); // 輸出 面積:100 re.areaHeight = 5; print("面積:${re.area}"); // 輸出 面積:50 }
類的繼承
子類能複寫父類的方法 getter和setter
class Person{ String name; num age; Person(this.name,this.age); void printPersonInfo(){ print("姓名:${this.name} 年齡:${this.age}"); } void work(){ print("我正在工做"); } } class Coder extends Person{ // 由於Person是重寫了構造函數,因此這裏也須要寫一下與父類關聯的構造函數 // 若是父類有多個構造函數 則須要選一個本身須要的 Coder(String name,num age,String grade):super(name,age){ // 經過代碼能夠看出,這麼寫的目的是當咱們在實例化Coder時也會將值傳遞給父類 // grade 是子類的屬性,因此不用將參數傳遞給父類 this.grade = grade; } String grade; void printCoderInfo(){ super.work(); // 調用父類的方法 print("姓名:${this.name} 年齡:${this.age} 等級:${this.grade}"); } @override // 重寫父類方法 void work() { print("我正在寫代碼"); } } void main(){ Coder code = Coder("zhangsan",20,"初級碼農"); code.printCoderInfo(); // 輸出 姓名:zhangsan 年齡:20 等級:初級碼農 code.work(); // 輸出 我正在寫代碼 }
抽象類。Dart中的抽象類主要是用於定義標準,子類能夠繼承抽象類,而後實現抽象類的接口。
若是隻是把抽象類做爲一個標準的話咱們須要用implements實現抽象類。
abstract class Person{ String name; int age; Person(this.name,this.age); work(); // 沒有實現方法體 這是一個抽象方法 抽象方法是必需要在子類中實現的 eat(){ print('吃飯'); } } class Coder extends Person{ Coder(String name, int age) : super(name, age); @override work(){ print("${this.name}在搬運代碼,他今年已經${this.age}了"); } } /* 在dart中普通類和抽象類均可以做爲接口被實現 使用關鍵字 implements dart的接口會將普通類或者是抽象類中的屬性或者方法都重寫一遍,因此咱們通常採用抽象類實現接口。 由於只有抽象類才能夠建立抽象方法。 */ class Engineer implements Person{ // 這裏就不用像繼承同樣須要實現父類的構造方法。 @override int age; @override String name; @override eat() { print("工程師在吃飯"); } @override work() { print("${this.name}在搞算法,他今年才${this.age}"); } } void main (){ Coder code = Coder("張三", 30); code.work(); // 輸出 張三在搬運代碼,他今年已經30了 Engineer eng = Engineer() ..name = "李四" ..age = 20 ..work(); // 輸出 李四在搞算法,他今年才20 }
多接口和mixins
經過implements的方式,能夠實現多接口。
abstract class A{ String a; printA(); } abstract class B{ String b; printB(); } class C implements A,B{ @override String a; @override String b; @override printA() { // TODO: implement printA return null; } @override printB() { // TODO: implement printB return null; } } // 這樣C類的對象就能夠同時實現 A B的的抽象方法
經過mixins實現多繼承,Dart是不支持多繼承,是沒法實現相似C++的多繼承的功能。
class A{ // mixins 不能有顯示的構造方法 其實這個也好理解 由於使用mixins繼承多個類的話,它也不知道用什麼構造方法 只能使用默認的了 // A.withName(){ // // } a(){ print('A.a()'); } } class B{ a(){ print('B.a()'); } b(){ print('B.b()'); } } class C{ a(){ print('C.a()'); } b(){ print('C.b()'); } c(){ print('C.c()'); } } class D extends A with B,C{ int count; // 能夠定義本身的屬性 } void main (){ var d = new D(); d.a(); // 輸出 C.a() 默認調用最後一個方法 } /*mixins的方式組合的類 是必需要繼承object的 A B C 就是不能繼承與任何的類 除了默認的object 若是想實現相似繼承的效果 咱們可使用接口的方式*/
泛型方法
T getData<T>(value){ return value; } print(getData("xingming")); // 輸出 xingming print(getData(20)); // 輸出 20 print(getData<String>(20)); // 報錯 由於指定的是string類型 可是傳入的是int類型 // 經過泛型方法咱們就能夠不用區分傳入的參數類型和輸出的參數類型。 var names = List<String>(); names.addAll(['1', '2', '3']); names.add(42); // 報錯
泛型類
經過指定類的泛型類型,來肯定輸入的數據類型是否正確
void main (){ LogList loglist = LogList<int>(); // 肯定泛型類型爲int類型,後續類中的類型判斷就是int類型 loglist.addData(1); loglist.addData("1"); // 報錯 loglist.printList(); LogList loglist_1 = LogList(); // 沒有肯定泛型類型 loglist_1.addData(1); loglist_1.addData("1"); // 沒有報錯 loglist_1.printList(); } class LogList<T>{ List list = List<T>(); void addData(T value){ list.add(value); } void printList(){ for (int i = 0;i<list.length;i++){ print(list[i]); } } }
泛型接口
void main (){ B b = B<int>(); b.pirntA(1); //b.pirntA("12"); // 報錯 } abstract class A<T>{ pirntA(T value); } class B<T> implements A<T>{ @override pirntA(T value) { print(value); } }
上面簡單的介紹了一些Dart語言的基礎語法知識,關於Dart中更深層次的內容,我會在之後的文章中再慢慢的剖析。關注公衆號,閱讀更多精彩技術文章。