Dart 語言簡述

Dart是一種「結構化的web編程」語言,Dart編程語言在全部現代瀏覽器和環境中提供高性能。Dart是谷歌開發的計算機編程語言,後來被ECMA認定爲標準。html

Dart重要的概念:mysql

一、全部的東西都是對象。不管是變量、數字、函數等都是對象。全部的對象都是實例。全部的對象都繼承自內置的Object類。這點相似於JAVA語言的「一切皆爲對象」。程序員

二、程序中指定數據類型使得程序合理地分配內存空間,並幫助編譯器進行語法檢查。可是,指定類型不是必須的。Dart語言是弱數據類型。web

三、Dart代碼在運行前解析。指定數據類型和編譯時的長列,能夠提升運行速度。算法

四、Dart程序有統一的程序入口:main()。這一點與JAVA、C/C++語言相像。sql

五、Dart沒有public、protected和private的概念。私有特性經過變量或函數加下下劃線來表示。mongodb

六、Dart的工具能夠檢查出警告信息(warning)和錯誤信息(errors)。警告信息只是代表代碼可能不工做,可是不會妨礙程序運行。錯誤信息能夠是編譯時的錯誤,也多是運行時的錯誤。編譯時的錯誤將阻止程序運行,運行時的錯誤將會以異常(execption) 的方式呈現。數據庫

七、Dart支持anync/await異步處理。編程

八、關鍵字json

       
abstract 2 dynamic 2 implements 2 show 1
as 2 else import 2 static 2
assert enum in super
async 1 export 2 interface 2 switch
await 3 extends is sync 1
break external 2 library 2 this
case factory 2 mixin 2 throw
catch false new true
class final null try
const finally on 1 typedef 2
continue for operator 2 var
covariant 2 Function 2 part 2 void
default get 2 rethrow while
deferred 2 hide 1 return with
do if set 2 yield 3

避免使用這些單詞做爲標識符。可是,若有必要,標有上標的關鍵字能夠是標識符:

  • 帶有上標1的單詞是上下文關鍵字,僅在特定位置有意義。它們在任何地方都是有效的標識符。

  • 帶有上標2的單詞是內置標識符。爲了簡化將JavaScript代碼移植到Dart,這些關鍵字在大多數地方都是有效的標識符,但它們不能用做類或類型名稱,也不能用做導入前綴。

  • 帶有上標3的單詞是與Dart 1.0發佈後添加的異步支持相關的有限保留字。不能在任何被標記asyncasync*sync*標記的函數體中使用awaityield做爲標識符。

表中的全部其餘單詞都是保留字,不能是標識符。

Dart語言的經常使用庫

包名 概述
dart:async 異步編程支持,提供Future和Stream類
dart:collection 對dart:core 提供更多的集合支持
dart:convert 不一樣類型(JSON、UTF-8)間的字符編碼、解碼支持
dart:core Dart語言內建的類型、對象以及dart語言核心的功能
darr:html 網頁開發用到的庫
dart:io 文件讀寫I/O相關操做的庫
dart:math 數字常量及函數,提供隨機數算法 
dart:svg 事件和動畫的矢量圖像支持

其中三個開發庫的使用頻率最高:

dart:core  核心庫,包含strings、numbers、collections、errors、dates、URIs等。

dart:html  網頁開發裏DOM相關的一些庫。

dart:io  I/O命令行使用的I/O庫。

dart:core庫時Dart語言初始已經包含的庫,其餘的任何庫在使用前都須要加上import語句。

變量與基本數據類型:

在Dart裏,變量聲明使用var關鍵字。在Dart語言裏一切且爲對象,因此若是沒有將變量初始化,那麼它的默認值爲null。

全局變量特色:全局變量常駐內存、全局變量污染全局
局部變量特色:不常駐內存會被垃圾機制回收、不會污染全局

一、常量和固定值

常量及固定值在開發中很常見。若是定義的變量不會變化,可使用final或const來指明。const是一個編譯時的常量;final的值只能被設定一次。

例如:第一行代碼設置了一個常量,若是第二行進行從新賦值,那麼將引起異常。

final username = "張三";  //定義了一個常量 //username = "李四"; //會引起一個錯誤

經過對const類型作四則運行將自動獲得一個const類型的值。下面代碼會獲得一個常量,計算圓的面積:

const pi = 3.1415926; const area = pi * 100 * 100;

能夠經過const來建立常量的值,就是說const[]自己是構造函數,示例代碼以下:

final stars = const []; const buttons = const [];

二、基本數據類型

Dart語言經常使用的基本數據類型包括:Number、String、Boolean、List、Map。

(1)Number類型:包括int整型, double浮點型

int和double類型都是num類型的子類。int類型不能包含小數點。

int必須是整型;double便可以是整型,也能夠是浮點型。

num類型包括的操做有:+,-,*,/,% 以及位移操做>>。num類型包括的經常使用方法有:abs、ceil和floor。

(2)String類型:字符串類型

String str = "This is flutter";

可使用三個單引號或雙引號來定義多行的String類型,在Flutter中咱們專門用來表示大文本塊。

var s1 = ''' ''' var s2 = """ """ //請注意這是一個用三個引號包裹起來的字符串,能夠用來添加多行數據

字符串類型拼接:

String str1 = "Hello"; String str2 = "World" print(str1 + str2); //Hello World
print(str1 + " " + str2); //Hello World

(3)Boolean類型

Dart是強bool類型檢查,只有bool類型的值是true才被認爲是true。有的語言裏0是false,大於0是true。在Dart語言裏則不是,值必須爲true或者false

var sex = ""; if(sex){ print("你的性別是!" + sex); }

上面的示例代碼編譯不能正常經過,由於sex變量是一個字符串,不是使用條件判斷語句,必須用bool類型才能夠。

(4)List類型

在Dart語言中,具備一系列相同類型的數據稱爲List對象。Dart裏的List對象相似於JavaScript語言的數組Array對象。

//第一種定義List方式
var list1 = [1, 2, 3]; //第二種定義List方式
var list2 = new List(); list2.add("a"); list2.add(123); list2.add("c"); //定義List指定類型
var list3 = new List<String>(); list3.add("a"); list3.add("b");

List經常使用屬性

length    長度
reversed    翻轉
isEmpty    是否爲空
isNotEmpty    是否不爲空


var arr = ["香蕉","蘋果","橘子"]; print(arr.length); //3
print(arr.reversed); //(橘子, 蘋果, 香蕉)
print(arr.isEmpty); //false
print(arr.isNotEmpty); //true

var newArr = arr.reversed.toList(); print(newArr); //[橘子, 蘋果, 香蕉]

List經常使用方法

add    增長
addAll    拼接數據
indexOf    查找 傳入具體值
remove    刪除 傳入具體值
removeAt    刪除 傳入索引值
fillRange    修改
insert(index,value);    指定位置插入
insertAll(index,list);    指定位置插入List
toList()     其餘類型轉換成List
join()     List轉換成字符串
split() 字符串轉換成List
forEach()
map
where
any
every














var arr = ["香蕉","蘋果","橘子"]; arr.add("桃子"); print(arr); //[香蕉, 蘋果, 橘子, 桃子]
arr.addAll(["西瓜","草莓"]); print(arr); //[香蕉, 蘋果, 橘子, 桃子, 西瓜, 草莓]
print(arr.indexOf("蘋果"));  //1 //indexOf查找不到的話,返回-1;查找到的話,返回索引值
arr.remove("西瓜"); print(arr); //[香蕉, 蘋果, 橘子, 桃子, 草莓]
arr.removeAt(3); print(arr); //[香蕉, 蘋果, 橘子, 草莓]
arr.fillRange(1, 2, "aaa"); //修改
print(arr); //[香蕉, aaa, 橘子, 草莓] 
arr.insert(2, "bbb"); //插入
print(arr); //[香蕉, aaa, bbb, 橘子, 草莓] 
arr.insertAll(1, ["123","456"]); //插入多個
print(arr); //[香蕉, 123, 456, aaa, bbb, 橘子, 草莓]
var arr = ["香蕉","蘋果","橘子"]; var str = arr.join("-"); //List轉換成字符串
print(str); //香蕉-蘋果-橘子
var newArr = str.split("-"); //字符串轉換成List
print(newArr); //[香蕉, 蘋果, 橘子] 

forEach:循環遍歷

List arr = ["香蕉","蘋果","橘子"]; arr.forEach((value){ print(value); });

map:經常使用於修改集合裏的數據

//循環遍歷修改List
List myNum = [1,3,5]; List newNum = new List(); for(var i = 0; i < myNum.length; i++){ newNum.add(myNum[i]*2); } print(newNum); //[2, 6, 10] //能夠用map來實現
List myNum = [1,3,5]; var newNum = myNum.map((value){ return value*2; }); print(newNum.toList()); //[2, 6, 10]

where:把知足條件的返回一個新的集合

List myNum = [1,3,4,5,7,8,9]; var newNum = myNum.where((value){ return value > 5; }); print(newNum.toList()); //[7, 8, 9]

any和every:判斷List裏有沒有知足條件的,有的話返回true或false

//any
List myNum = [1,3,4,5,7,8,9]; var f = myNum.any((value){ //只要集合裏有知足條件的就返回true
    return value >5; }); print(f); //true //every
List myNum = [1,3,4,5,7,8,9]; var f = myNum.every((value){ //集合裏面每個都要知足條件返回true,不然返回false
    return value >5; }); print(f); //false

(5)Map類型

Map經常使用屬性:

keys    獲取全部的key值
values    獲取全部的value值
isEmpty    是否爲空
isNotEmpty     是否不爲空


var person = { "name":"張三", "age":20, "sex":"", }; print(person.keys.toList()); //[name, age, sex]
print(person.values.toList()); //[張三, 20, 男]
print(person.isEmpty); //fales
print(person.isNotEmpty); //true

Map經常使用方法:

remove(key) 刪除指定key的數據
addAll({...}) 合併映射 給映射增長屬性
containsValue 查看映射內的值 返回true/false
forEach
map
where
any
every






var person = { "name":"張三", "age":20, "sex":"", }; person.addAll({"work":["程序員","外賣員"],"height":170}); print(person); //{name: 張三, age: 20, sex: 男, work: [程序員, 外賣員], height: 170}
person.remove("sex"); print(person); //{name: 張三, age: 20, work: [程序員, 外賣員], height: 170}
print(person.containsValue("張三")); //true

forEach():

var person = { "name":"張三", "age":20, "sex":"", }; person.forEach((key,vlaue){ print("$key--$vlaue"); }); //若是是一行代碼也能夠用=>
person.forEach((key,vlaue)=>print("$key--$vlaue"));

Map類型將key和value關聯在一塊兒,也就是鍵值對。像其餘支持Map的編程語言同樣,key必須是惟一的。

var week = { "Monday" : "星期一", "Tuesday" : "星期二", "Wednesday" : "星期三", "Thursday" : "星期四", "Friday" : "星期五", "Saturday" : "星期六", "Sunday" : "星期日", };
print(week["Monday"]);
//也可使用Map對象的構造函數Map()來建立Map對象 var week = new Map(); week["Monday"] = "星期一"; week["Tuesday"] = "星期二"; week["Wednesday"] = "星期三"; week["Thursday"] = "星期四"; week["Friday"] = "星期五"; week["Saturday"] = "星期六"; week["Sunday"] = "星期日";

添加新的key-value對,再給week添加一個值,注意,其中0爲鍵不是數組的下標索引:week['0'] = '星期一';

檢查key是否在Map對象中:assert(week['Monday'] == null);

使用length來獲取key-value對的數量,如今咱們調用length輸出長度爲8,緣由是剛纔後面又添加了一個數據(0),代碼以下:

var week = new Map(); week['Monday'] = "星期一"; week['Tuesday'] = "星期二"; week['Wednesday'] = "星期三"; week['Thursday'] = "星期四"; week['Friday'] = "星期五"; week['Saturday'] = "星期六"; week['Sunday'] = "星期日"; week['0'] = '星期一'; print(week); //{Monday: 星期一, Tuesday: 星期二, Wednesday: 星期三, Thursday: 星期四, Friday: 星期五, Saturday: 星期六, Sunday: 星期日, 0: 星期一}
    print(week.length); //8

(6)Set:表示對象的集合,其中每一個對象只能出現一次。

Set:用它最主要的功能就是去除數組重複內容
Set是沒有順序且不能重複的集合,因此不能經過索引去獲取值

var ss = new Set(); ss.add("香蕉"); ss.add("蘋果"); ss.add("香蕉"); print(ss); //{香蕉, 蘋果}
print(ss.toList()); //[香蕉, 蘋果]

var arr = new List(); arr.add("香蕉"); arr.add("蘋果"); arr.add("香蕉"); print(arr); //[香蕉, 蘋果, 香蕉] 

var arr = ["香蕉","蘋果","橘子","香蕉","蘋果","香蕉","蘋果"]; var ss = new Set(); ss.addAll(arr); print(ss.toList()); //[香蕉, 蘋果, 橘子]
Set也能夠用forEach()循環遍歷:
var ss = new Set(); ss.addAll([11,22,333]); ss.forEach((value){ print(value); }); //若是隻有一行代碼能夠用=>
ss.forEach((value)=>print(value));

is 關鍵詞來判斷類型:

//加入str是後臺返回的數據,不知道是什麼類型,能夠用is來判斷
var str = '1234'; if(str is String){ print('是string類型'); }else if(str is int){ print('是int類型'); }else{ print('是其餘類型'); } //是string類型

Dart類型轉換:

(1)Number類型轉換爲String類型:toString()

var myNum = 123; var str = myNum.toString(); print(str is String);  //true

(2)String類型轉換爲Number類型:parse()

String str = "123"; var myNum = double.parse(str); //String類型轉換Number類型的時候建議用double,用int的話,若是有小數會報錯 print(myNum is double);  //true

(3)其餘類型轉換成Boolean類型

isEmpty:判斷字符串是否爲空 

var str = 'xxx'; if(str.isEmpty){ print('str爲空'); }else{ print('str不爲空'); } //str不爲空
var myNum1 = 0/0; if(myNum1.isNaN){ print('NaN'); }else{ print(myNum1); } //NaN 

var myNum2 = 1; if(myNum2.isNaN){ print('NaN'); }else{ print(myNum2); } //1

三、函數

Dart是一個面向對象的語言,因此函數也是對象,函數屬於Function對象。

函數能夠像參數同樣傳遞給其餘函數,這樣便於作回調處理。

//判斷兩個字符串是否相等
bool equal(String str1, String str2) { retrue str1 == str2; }

(1)可選參數

將參數使用中括號[]括起來,用來代表是可選位置參數。

例如:總共傳入了三個參數,其中name和sex是必須傳入的參數,from參數能夠不傳,代碼以下:

//獲取用戶信息
String getUserInfo(String name, String sex, [String from]) { var info = '$name 的性別是 $sex'; if(from != null){ info = ‘$info來自$from’; } return info; } void test(){ pring(getUserInfo(‘小王’, '')); }

(2)參數默認值

若是參數指定了默認值,當不傳入值時,函數裏會使用這個默認值。若是傳入了值,則用傳入的值取代默認值。一般參數的默認值爲null。

改造上面獲取用戶信息的例子,給from參數賦上默認值,代碼以下:

//獲取用戶信息 使用等號= 來設置默認位置參數
String getUserInfo(String name, String sex, [String from = '中國']) { var info = '$name 的性別是 $sex'; if(from != null){ info = ‘$info來自$from’; } return info; } void test(){ pring(getUserInfo(‘小王’, '')); }

 調用上面的test()方法能夠輸出「小王的性別是男來自中國」。

(3)main函數

Flutter應用程序必需要有一個main函數,和其餘語言同樣做爲程序的入口函數。 

以下代碼表示應用要啓動MyApp類:void main() => runApp(MyApp());

(4)函數返回值

在Dart語言中,函數的返回值有以下特色:

  • 全部的函數都有返回值
  • 若是沒有指定函數返回值,則默認的返回值是null
  • 沒有返回值的函數,系統會在最後添加隱式的return語句

(5)箭頭函數

只有一條語句的時候能夠用箭頭函數:

List arr = ["香蕉","蘋果","橘子"]; arr.forEach((value){ print(value); }); //箭頭函數
arr.forEach((value)=>print(value));

例子1:修改數組裏的數據,大於2的值乘以2

List myNum = [1,2,3,4,5]; var newNum = myNum.map((value){ if(value > 2){ return value*2; } return value; }); print(newNum.toList()); //用箭頭函數實現
List myNum = [1,2,3,4,5]; var newNum2 = myNum.map((value) => value>2 ? value*2 : value); print(newNum2.toList());

例子2:定義一個方法isEvenNumber來判斷一個數是不是偶數,定義一個方法打印1到n之間的偶數。

//定義一個方法isEvenNumber來判斷一個數是不是偶數
bool isEvenNumber(int n){ if(n%2 == 0){ return true; } return false; } //打印1到n之間的偶數
printNum(int n){ for(var i = 1; i <= n; i++){ if(isEvenNumber(i)){ print(i); } } } printNum(10); //2 4 6 8 10

四、運算符

Dart支持各類類型的運算符,而且其中的一些操做符還能進行重載。完整的操做符以下表

描述 運算符
一元后綴 expr++ expr-- () [] . ?.
一元前綴 -expr !expr ~expr ++expr --expr
乘法類型 * / % ~/
加法類型 + -
移動位運算 << >>
位運算 &
異或位運算 ^
位運算 |
關係和類型測試 >= <= > < as is is!
等式 == !=
邏輯與 &&
邏輯或 ||
條件 expr1 ? expr2 : expr3
級聯 ..
賦值 = *= /= ~/= %= += -= <<= >>= &= ^= |= ??=

使用運算符時能夠建立表達式,如下是運算符表達式的一些示例:
a++ a-- a + b a = b a == b expr ? a : b a is T

注意使用運算符時的順序。在運算符表中,操做符的優先級由上到下逐個減少,上面行內的操做符優先級大於下面行內的操做符。例如,「乘法類型」操做符%的優先級比"等階"操做符==要高,而==操做符的優先級又比"邏輯與"操做符&&要高。

//使用括號來提升可讀性
if((n % i == 0) && (d & i == 0)); //難以閱讀,可是和上面等階
if(n % i == 0 && d & i == 0);

提示:對於二元運算符,其左邊的操做數將會決定使用的操做符的種類。例如:當你使用一個Vector對象以及一個Point對象時,aVector + aPoint使用的+是由Vector所定義的。

(1)算術運算符

 Dart支持經常使用的算術運算符:

操做符  含義
+
-
-expr 一元減號,也命名爲負號(使後面表達式的值反過來)
*
/
~/ 返回一個整數值的除法
% 取餘,除法剩下的餘數
++var var=var+1 表達式的值爲var+1
var++ var=var+1 表達式的值爲var
--var var=var-1 表達式的值爲var-1
var-- var=var-1 表達式的值爲var

示例代碼以下:

assert(3 + 6 == 9); assert(3 - 6 == -3); assert(3 * 6 == 18); assert(7 / 2 == 3.5); //結果是浮點型
assert(5 ~/2 == 2); //結果是整形
assert(5 % 2 == 1); //求餘數

var a, b; a = 0; b = ++a; //在b得到其值以前自增a
assert(a == b); //1 == 1
 a = 0; b = a++; //在b得到值後自增a
assert(a != b); //1 != 0
 a = 0; b = --a; //在b得到其值以前自減a
assert(a == b); //-1 == -1
 a = 0; b = a--; //在b得到值後自減a
assert(a != b); //-1 != 0
var a = 10; var b = a++; //先把a的值賦值給b,而後在自增,因此b=10,a=11
print(a); //11
print(b); //10

var a = 10; var b = ++a; //先進行自增,而後再賦值給b,因此都是11
print(a); //11
print(b); //11

注意:在賦值運算裏,若是++或--寫在前面,這時先運算,再賦值;若是++或--寫在後面的時候,先賦值再進行運算。

(2)關係運算符

操做符 含義
== 等於
!= 不等於
> 大於
< 小於
>= 大於等於
<= 小於等於

有時候須要判斷兩個對象是否相等,請使用==運算符。

int a = 5; int b = 3; print(a==b); //false
    print(a!=b); //true
    print(a>b); //true
    print(a<b); //false
    print(a>=b); //true
    print(a<=b); //false

(3)類型測試操做符

as、is和is! 操做符在運行時用於檢查類型很是方便,含義以下:

操做符 含義
as 類型轉換
is 當對象時相應類型時返回true
is! 當對象不是相應類型時返回true

若是obj實現了T所定義的接口,那麼obj is T 將返回true。

使用as操做符能夠把一個對象轉換爲制定類型,前提是可以轉換。轉換以前用is判斷一下更保險。以下代碼:

if(user is User){ //類型檢測
  user.name = 'Flutter'; } //若是能肯定user時User的實例,則能夠經過as直接簡化代碼:
(user as User).name = ‘Flutter’;

注意:上面兩段代碼並不相等,若是user的值爲null或者不是一個User對象,則第一段代碼不會作出任何事情,第二段代碼會報錯。

is 類型判斷:

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } } void main(){ User user = new User("張三",20); if(user is User){ //判斷user這個對象是否屬於User這個類
    user.name = "李四"; } user.printInfo(); //李四----20
}

as 類型轉換:

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } } void main(){ var user = ''; user = new User("張三",20); //老版本 user.printInfo(); 不會執行,由於不知道user屬於什麼類型 //因此user用as強制轉換爲User類型
  (user as User).printInfo(); //張三----20
}

? 條件運算符:

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } } void main(){ User user1 ; user1?.printInfo(); //?表示若是對象是空的話不會調用這個方法
 User user2 = new User("張三",20); user2?.printInfo(); //張三----20 //?判斷非空調用方法
}

 

(4)賦值操做符

可使用 = 運算符賦值。要僅在變量爲null時賦值,請使用 ??= 運算符。以下代碼所示:

//賦值給a
a = value;
c = a + e;
//若是b爲空,則將值分配給b;不然b保持不變 b??= value; //例如
int b = 10;
b??= 20;
print(b); //10 由於b不爲空,因此b的值仍是10 //例如
int b;
b??= 20;
print(b); //20





複合賦值運算符:

諸如+=之類的複合賦值運算符將操做符與賦值相結合。如下是複合賦值運算符的工做方式:

複合賦值符 等式表達式
a op b a = a op b
a += b a = a + b
a -= b a = a - b
var a = 3; a += 5; print(a); //8

(5)邏輯運算符

可使用邏輯運算符反轉或組合布爾表達式。邏輯運算符以下所示:

操做符 含義
!expr 反轉如下表達式(將false更改成true,反之亦然)
|| 邏輯或
&& 邏輯與

示例代碼以下:

if(!expr && (test == 1 || test == 8)) { ...... }

(6)位運算符

一般咱們指位運算爲<< 或 >> 移動位運算,經過操做位的移動來達到運算的目的,而&、|、^、~expr也是操做位來達到運算的目的。

操做符 含義
&
|
^ 異或
~expr 一元位補碼(0s變爲1s;1s變爲0s)
<< 左移
>> 右移

示例代碼以下:

final value = 0x22; final bitmask = 0x0f; assert((value & bitmask) == 0x02); //
assert((value & -bitmask) == 0x20); //與非
assert((value | bitmask) == 0x2f); //
assert((value ^ bitmask) == 0x2d); //異或
assert((value << 4) == 0x220); //左移
assert((value >> 4) == 0x02); //右移

(7)條件表達式

Dart由兩個運算符,可用來簡明地評估可能須要if-else語句的表達式。以下代碼即爲一種條件表達式,也能夠稱爲三元表達式,若是條件爲真,返回expr1,不然返回expr2.

condition ? expr1 : expr2;
//例如 var a = true ? 123 : 456;

第二種以下表示,若是expr1爲非空,則返回其值;不然,計算並返回expr2的值。

expr1 ?? expr2;
//例如
var a;
var b = a ?? 10;
print(b); //a爲空,計算並返回expr2的值10賦給b
//例如
var a = 22;
var b = a ?? 10; print(b); //a不爲空,返回a的值22賦給b




(8) 級聯操做(連綴)

級聯操做用兩個點(..)表示,可對同一對象執行一系列操做。相似於Java語言裏點點點處理或JavaScript裏的Promise的then處理。級聯操做主要的目的是爲了簡化代碼。

querySelector('#btnOK') { //獲取一個id爲btnOK的按鈕對象
    ..text = '肯定'  //使用它的成員
    ..classes.add('ButtonOKStyle'); ..onClick.listen((e) => window.alert('肯定')); } //至關於

var button = querySelector('#btnOK'); button.text = '肯定'; button.classes.add(' ' ButtonOKStyle ' '); button.onClick.listen((e) => window.alert('肯定'));

第一個方法調用querySelector,返回一個按鈕對象,而後再設置它的文本爲「肯定」,再給這個按鈕添加一個樣式叫「ButtonOKStyle」,最後在監聽單擊事件,事件彈出一個顯示「肯定」的Alert。

還用前面的例子:

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } } void main(){ User user = new User("張三",20); uesr.printInfo(); //張三----20
  user.name = "李四"; user.age = 30; user.printInfo(); //李四----30 //上面的三行代碼能夠簡寫爲
  user..name = "李四" ..age = 30 ..printInfo(); //李四----30
}

注意:嚴格來講,級聯的「雙點」符號不是運算符。這只是Dart語法的一部分。

五、流程控制語句

Dart語言的流程控制語句以下:if和else、for(循環)、while和do-while(循環)、break和continue、switch和case、assert(斷言)、try-catch和throw。

(1)if和else

Dart支持if及else的多種組合。

String today = 'Monday'; if(today == 'Monday') { print('今天是星期一'); }else if(today == 'Tuesday') { print('今天是星期二'); }else { print('今天是個好日子'); } //輸出'今天是星期一',條件語句走到第一條判斷就中止了。

(2)for(循環)

//打印出0-50的偶數
for(var i = 0; i <= 50; i++){ if(i%2 == 0){ print(i); } }
//求1到100的和
var sum = 0; for(var i = 0; i <= 100; i++){ sum += i; } print(sum); //5050 //計算5的階乘 1*2*3*4*5
var sum = 1; for(var i = 1; i <= 5; i++){ sum *= i; } print(sum); //120
//打印List裏的內容
List arr = ['張三','李四','王五']; for(var i = 0; i < arr.length; i++){ print(arr[i]); } 
//也能夠用for-in實現
List arr = ['張三','李四','王五']; for(var item in arr){ print(item); } 
//打印List裏的內容
List arr = [ {"title":"新聞1"},{"title":"新聞2"},{"title":"新聞3"}, ]; for(var i = 0; i < arr.length; i++){ print(arr[i]["title"]); }
//打印List裏的內容
List arr = [ { "card":"國內", "news":[ {"title":"國內新聞1"},{"title":"國內新聞2"},{"title":"國內新聞3"} ] }, { "card":"國際", "news":[ {"title":"國際新聞1"},{"title":"國際新聞2"},{"title":"國際新聞3"} ] }, ]; for(var i = 0; i < arr.length; i++){ print(arr[i]["card"]); for(var j = 0; j < arr[i]["news"].length; j++){ print(arr[i]["news"][j]["title"]); } }

下面舉例說明,首先定義了一個字符串「Hello Dart」,而後使用for循環向message變量裏寫入5個一樣的字符「!」。

var message = new StringBuffer('Hello Dart'); for(var i = 0; i < 5; i ++) { message.write(i); } print(message); //輸出「Hello Dart!!!!!」,注意值是字符串向尾部添加的。 //除了常規的for循環外,針對能夠序列化的操做數,可使用forEach()方法,當不關心操做數的當前下標時,forEach()方法師很簡便的。
var arr = [0, 1, 2, 3, 4, 5, 6]; for(var v in arr){ print(v); } //按序列輸出 0 1 2 3 4 5 6

(3)while和do-while(循環)

下面舉例說明while循環,其中定義了一個變量temp,temp在循環體內自動加1,當條件(temp<5)不知足時會推出循環,代碼以下:

var _temp = 0; while(_temp < 5) { print('這是一個循環:' + (_temp).toString()); _temp ++; } var _temp = 0; do{ print(‘這是一個循環:’ + (_temp).toString()); _temp ++; }while(_temp < 5); //都輸出 //flutter:這是一個循環:0 //flutter:這是一個循環:1 //flutter:這是一個循環:2 //flutter:這是一個循環:3 //flutter:這是一個循環:4
//打印0到10
var i = 0; while(i <= 10){ print(i); i++; } //打印1到100的和
var sum = 0; var i = 1; while(i <= 100){ sum += i; i++; } print(sum); //5050 //do-while實現
var sum = 0; var i = 1; do{ sum += i; i++; }while(i <= 100); print(sum); //5050

while和do-while的區別:

while:先判斷第一次循環條件,不成立的狀況下,不執行語句;

do-while:先執行一次語句,再判斷第一次循環條件。

注意:死循環的問題。

(4)break和continue:

break能夠用在switch case中,也能夠用在for循環和while循環中。

break語句功能:
①、在switch語句中使流程跳出
②、在循環語句中使流程跳出當前循環,遇到break循環終止,後面代碼也不會再執行;在多層循環中,一個break語句只能向外跳一層



continue能夠用在for循環以及while循環中,可是不建議用在while循環裏,不當心容易形成死循環。

continue語句的功能:
只能在循環語句中使用,使本次循環結束,即跳過循環體,從下面還沒有執行的語句,接着進行下去


break用來跳出循環,改造前面的循環例子:

var arr = [0, 1, 2, 3, 4, 5, 6]; for(var v in arr){ if(v == 2){ break; } print(v); } //當v等於2的時候跳出循環,因此輸出「0,1」。如今把break改成continue

var arr = [0, 1, 2, 3, 4, 5, 6]; for(var v in arr){ if(v == 2){ //break;
     continue; } print(v); } //改成continue後,當v等於2的時候只是跳出本次循環,代碼還會繼續往下執行,因此輸出結果是「0,1,3,4,5,6」
//continue例子
for(var i = 0; i <=10; i++){ if( i == 4){ continue; //跳出本次循環體,繼續下面的循環
 } print(i); } //0 1 2 3 5 6 7 8 9 10 //若是i等於4跳出循環
for(var i = 0; i <=10; i++){ if( i == 4){ break; } print(i); } //0 1 2 3 //break跳出一層循環
for(var i = 0; i < 3; i++){ print("外層---$i"); for(var j = 0; j < 3; j++){ if(j == 1){ break; } print("裏層$j"); } } //外層---0 //裏層0 //外層---1 //裏層0 //外層---2 //裏層0

(5)switch和case

Dart中switch/case語句使用==操做來比較整數、字符串或其餘編譯過程當中的常量,從而實現分支的做用。switch/case語句的先後操做數必須是相同類型的對象實例。每個非空的case子句最後都必須跟上break語句。

String today = 'Monday'; switch(today) { case 'Monday' : print('星期一'); break; case 'Tuesday' : print('星期二'); break; }

(6)assert(斷言)

Dart語言經過使用assert語句來中斷正常的執行流程,當assert判斷的條件爲false時發生中斷。assert判斷的條件是任何能夠轉化爲boolean類型的對象,即便是函數也能夠。若是assert的判斷爲true,則繼續執行下面的語句;反之則會拋出一個斷言錯誤異常AssertionError。

//肯定變量的值不爲null
assert(text != null);

六、方法

(1)自定義方法

自定義方法基本格式:

返回類型 方法名稱(參數1,參數2...){ 方法體 return 返回值; }
//定義方法
void printInfo(){ //void 是沒有返回值的
    print("我是一個自定義方法"); } //運行方法
printInfo();
int getNum(){ //int是方法的返回值類型
    var myNum = 123; return myNum; } var n = getNum(); //調用方法,併發返回值賦給n
print(n); //123
 String printInfo(){ return 'This is string'; } var str = printInfo(); print(str); //This is string
 List getList(){ return ["aa","bb","cc"]; } print(getList()); //[aa, bb, cc]

調用方法傳參:

例子1:定義一個方法,求1到這個數的全部的和

int sumNum(n){ var sum = 0; for(var i = 0; i <= n; i++){ sum += i; } return sum; } print(sumNum(10)); //55
print(sumNum(100)); //5050

例子2:定義一個打印用戶信息的方法

String printUserInfo(String name, int age){ //形參
    return "姓名:$name--年齡:$age"; } print(printUserInfo("張三",20)); //實參

例子3:定義一個帶可選參數的方法

String printUserInfo(String name, [int age]){ //[]可選參數
    if(age != null){ return "姓名:$name--年齡:$age"; } return "姓名:$name--年齡:保密"; } print(printUserInfo("張三")); print(printUserInfo("李四",20));

例子4:定義一個帶默認參數的方法

String printUserInfo(String name, [int age, String sex = ""]){ if(age != null){ return "姓名:$name--年齡:$age--性別:$sex"; } return "姓名:$name--年齡保密--性別:$sex"; } print(printUserInfo("張三")); //姓名:張三--年齡保密--性別:男 
print(printUserInfo("李四",20)); //姓名:李四--年齡:20--性別:男
print(printUserInfo("王五",20,"")); //姓名:王五--年齡:20--性別:女 //有個問題,若是實現只寫名字和性別會報錯,不能中間空一項,必須三項都寫

例子5:定義一個命名參數的方法

//用命名參數{}不會出現上面問題,不過實參要寫上key
String printUserInfo(String name, {int age, String sex = ""}){ if(age != null){ return "姓名:$name--年齡:$age--性別:$sex"; } return "姓名:$name--年齡保密--性別:$sex"; } print(printUserInfo("張三")); //姓名:張三--年齡保密--性別:男 
print(printUserInfo("李四",age:20)); //姓名:李四--年齡:20--性別:男
print(printUserInfo("王五",sex:"")); //姓名:王五--年齡保密--性別:女

例子6:實現一個把方法當作參數的方法

//把fn1賦值給了fn,而後調用fn2執行裏面的fn,打印出裏面的「String」 
fn1(){ print("String"); } fn2(fn){ fn(); } //調用fn2方法,把fn1方法當作參數傳入
fn2(fn1); //fn1 //更好理解
var fn = (){ print("我是一個匿名方法"); }; fn();

(2)匿名方法

var printNum = (int n){ print(n+2); }; printNum(3); //5

(3)自執行方法

格式:

((){ ... })(); //或者
(){ ... }();

例子:

((n){ print(n); })(12); //12

(4)方法的遞歸

例子1:經過方法的遞歸求5的階乘

var sum = 1; fn(n){ sum *= n; if(n == 1){ return; } fn(n-1); } fn(5); print(sum); //120

例子2:經過方法的遞歸求1到100的和

var sum = 0; fn(n){ if(n == 0){ return; } sum += n; fn(n-1); } fn(100); print(sum); //5050

(5)閉包

閉包的寫法:函數嵌套函數,並return裏的函數,這樣就造成了閉包

想實現的功能:常駐內存、不污染全局

fn(){ var a = 123; //不會污染全局,常駐內存
    return(){ a++; print(a); }; } var b = fn(); b(); //124
b(); //125
b(); //126

七、異常處理

異常是表示發生了意外的錯誤,若是沒有捕獲異常,引起異常的隔離程序將被掛起。而且程序將終止。

Dart代碼能夠拋出並捕獲異常,但與Java相反,Dart的全部異常都是未檢查的異常。方法不聲明它們可能拋出那些異常,也不須要捕獲任何異常。

Dart提供了異常和錯誤類型以及許多預約義的子類型。固然,也能夠定義本身的異常。而後,Dart程序能夠拋出任何非空對象。

(1)拋出異常

下面是一個拋出或引起異常的例子:

throw FormatException('拋出一個FormatException異常');

你也能夠拋出任意對象: 

throw '數據非法!';

提示:穩定健壯的程序必定是作了大量異常處理的,因此建議你在編寫程序時儘可能考慮到可能發生異常的狀況。

(2)捕獲異常

你能夠指定一個或兩個參數來捕獲異常(catch),第一個是拋出的異常,第二個是堆棧跟蹤(StackTrace 對象)。以下代碼所示:

try { //...
      }on Exception catch (e) { print('Exception details:\n $e'); }catch (e, s) { pring('Exception details:\n $e'); pring('Stack trace:\n $s'); } //上面的代碼第一個catch用來捕獲異常詳細信息,第二個catch是堆棧跟蹤信息
//例如 
String str = ""; try{ var myNum = double.parse(str); print(myNum is double); }catch(e){ print(0); } //str爲空,因此轉換Number類型失敗,打印0

(3)Finally

要確保某些代碼可以運行,不管是否拋出異常,請使用finally子句。若是沒有catch子句匹配異常,則異常在finally子句運行後傳播。以下面代碼所示,在最下面加上了finally語句:

try { //...
      }on Exception catch (e) { print('Exception details:\n $e'); }catch (e, s) { pring('Exception details:\n $e'); pring('Stack trace:\n $s'); }finally { print('Do some thing:\n'); }

八、面向對象 (面向對象的三大特性:封裝、繼承、多態)

Dart做爲高級語言支持面向對象的不少特性,而且支持基於mixin的繼承方式。基於mixin的繼承方式是指:一個類能夠繼承自多個父類,至關於其餘語言裏的多繼承。全部的類都有同一個基類Object,這個特性相似於Java語言,Java全部的類也都是繼承自Object,也就是說一切皆爲對象。全部的對象都是類的實例,而且全部的類都是Object的子類。

使用new語句實例化一個類,以下所示:

//實例化了一個User類的對象user
var user = new User('張三', 20);

(1)實例化成員變量

定義一個User類,在裏面添加兩個成員變量name和age,代碼以下:

class User{ String name; //name成員變量
  String age; //age成員變量
}

類定義中全部的變量都會隱式的定義setter方法,針對非空的變量會額外增長getter方法。實例化成員變量請參考以下代碼:

class User{ String name; //name成員變量
  Int age; //age成員變量
} main() { var user = new User(); user.name = '張三'; //至關於使用了name的setter方法
  user.age = 20; }
class User{ String name = "張三"; int age = 20; void getInfo(){ //print("$name----$age");
        print("${this.name}----${this.age}"); } void setInfo(int age){ this.age = age; } } void main(){ //實例化
    var user = new User(); //也能夠指定類型 User user = new User();
    print(user.name); //張三
    user.getInfo(); //張三----20
    user.setInfo(25); user.getInfo(); //張三----25
}

私有屬性、私有方法:

私有屬性:私有屬性須要單獨一個文件纔可使用

例子:新建Animal.dart文件

Animal{ String _name; //私有屬性
    int age; Animal(this._name, this.age); }

在main.dart文件裏引入Animal.dart文件

import '../test/Animal.dart'; void main(){ Animal a = new Animal("小狗", 3); print(a._name); //由於_name是私有屬性,因此會報錯
   print(a.age); //3
}

利用公有方法訪問私有屬性 

仍是上面的例子:

Animal{ String _name; //私有屬性
    int age; Animal(this._name, this.age); //公有方法
 String getName(){ return this._name; } } 
import '../test/Animal.dart'; void main(){ Animal a = new Animal("小狗", 3); print(a._name); //由於_name是私有屬性,因此會報錯
   print(a.age); //3
   print(a.getName()); //小狗
}

私有方法也是同理,能夠經過公有方法間接的訪問私有方法:

Animal{ String _name; //私有屬性
    int age; Animal(this._name, this.age); //私有方法
    void _run(){ print("這是個私有方法"); } getRun(){ this._run(); //類裏面方法的相互調用
 } }
import '../test/Animal.dart'; void main(){ Animal a = new Animal("小狗", 3); print(a._name); //由於_name是私有屬性,因此會報錯
   print(a.age); //3
   print(a.getName()); //小狗 //間接的調用私有方法
   a.getRun(); //這是一個私有方法
}

靜態屬性、靜態方法:靜態方法不能訪問非靜態成員,非靜態方法能夠訪問靜態成員以及非靜態成員

例子:

class User{ static String name = "張三"; int age = 20; static void show(){ //靜態方法
 print(name); print(this.age); //報錯,靜態方法不能夠訪問非靜態成員
 } void printInfo(){ //非靜態方法能夠訪問靜態成員以及非靜態成員
        print(name); //訪問靜態屬性
        print(this.age); //訪問非靜態屬性
        show(); //調用靜態方法
 } } void main(){ //靜態屬性和方法不用實例化,能夠直接調用
    print(User.name); //張三
    User.show(); //張三
    User user = new User(); //非靜態屬性和方法須要實例化
    user.printInfo(); //張三 //20 //張三
}

(2)構造函數

①默認構造函數

class User{ String name = "張三"; int age = 20; //默認構造函數
 User(){ print("這是構造函數裏面的內容,這個方法在實例化的時候觸發"); } } main(){ //實例化
    User user = new User(); //運行,自動打印出:這是構造函數裏面的內容,這個方法在實例化的時候觸發
}

②常規構造函數

構造函數是用來構造當前類的函數,是一個特殊的函數,函數名稱必需要和類名相同才行。以下代碼爲User類添加了一個構造函數,函數裏給User類的兩個成員變量初始化了值:

class User{ String name; int age; User(String name, int age) { this.name = name; this.age =age; } } //this關鍵詞指向了當前類的實例,上面的代碼能夠簡化爲:

class User{ String name; int age; User(this.name, this.age); }

例子:

class User{ String name; int age; User(this.name, this.age); void printInfo(){ print("${this.name}----${this.age}"); } } void main(){ User user1 = new User("張三", 20); user1.printInfo(); //張三----20 
   User user2 = new User("李四", 25); user2.printInfo(); //李四----25 
}

③命名的構造函數

使用命名構造函數從另外一類或現有的數據中快速實現構造函數,代碼以下:

class User { String name; int age; User(this.name, this.age); //命名構造函數
 User.fromJson(Map json) { name = json['nage']; age = json['age']; } }

例子:

class User { String name; int age; User(this.name, this.age); //命名構造函數,能夠多個
 User.now(){ print("我是命名構造函數"); } User.setInfo(String name, int age){ this.name = name; this.age = age; } void printInfo(){ print("${this.name}----${this.age}"); } } void main(){ //調用命名構造函數
    User user1 = new User.now(); //我是命名構造函數
    User user2 = new User.setInfo("李四",30); user2.printInfo(); //李四----30
}

通常把類單獨離成一個模塊(一個dart文件),使用的時候引入這個dart文件就能夠了。

④構造函數初始化列表(先賦值再執行構造函數)

除了調用父類的構造函數,也能夠經過初始化列表在子類的構造函數運行前來初始化實例的成員變量值。代碼以下:

class User { final String name; final int age; User(name, age) : name = name, age = age; } main() { var p = new User('張三', 20); }

例子:

class Rect{ num height; num width; Rect():height=2, width=10{ print("${this.height}----${this.width}"); } getArea(){ return this.height * this.width; } } void main(){ Rect r = new Rect(); print(r.getArea()); } //2----10 //20

(3)讀取和寫入對象

get()和set()方法是專門用於讀取和寫入對象的屬性方法,每個類的實例,系統都隱式地包含有get()和set()方法。這和不少語言裏的VO類類似。

get例子:

class Rect{ num height; num width; Rect(this.height,this.width); area(){ return this.height * this.width; } } void main(){ Rect r = new Rect(10, 4); print("面積:${r.area()}"); //面積:40
} //使用get
class Rect{ num height; num width; Rect(this.height,this.width); get area{ return this.height * this.width; } } void main(){ Rect r = new Rect(10, 4); print("面積:${r.area}"); //面積:40 //注意調用直接經過訪問屬性的方式訪問area
}

set例子:

class Rect{ num height; num width; Rect(this.height,this.width); get area{ return this.height * this.width; } set areaHeight(value){ this.height = value; } } void main(){ Rect r = new Rect(10, 4); r.areaHeight = 6; print("面積:${r.area}"); //面積:24
}

例如,定義一個矩形的類,有上、下、左、右四個成員變量:top、bottom、left、right,使用get及set關鍵字分別對right及bottom進行獲取和設置值。代碼以下:

class Rectangle { num left; num top; num width; num height; Rectangle(this.left, this.top, this.width, this.height); //獲取right值
  num get right  => left + width; //設置right值 同時left也發生變化
  set right(num value)  => left = value - width; //獲取bottom值
  num get bottom => top + height; //設置bottom值 同時top也發生變化
  set bottom(num value)  => value - height; } main(){ var rect = new Rectangle(3, 4, 20, 15); print('left:' + rect.left.toString()); print('right:' + rect.right.toString()); rect.right = 30; print('更改right值爲30'); print(‘left:’ + rect.left.toString()); print('right:' + rect.right.toString()); print('top:' + rect.top.toString()); print('bottom:' + rect.bottom.toString()); rect.bottom= 50; print('更改bottom值爲50'); print('top:' + rect.top.toString()); print('bottom:' + rect.bottom.toString()); } //對應的輸出爲: //flutter: left:3 //flutter: right:23 //flutter: 更改right值爲30 //flutter: left:10 //30-20 //flutter: right:30 //flutter: top:4 //flutter: bottom:19 //flutter: 更改bottom值爲50 //flutter: top:35 //50-15 //flutter: bottom:50

(4)重載操做

編寫一個例子,定義一個Vector向量類,編寫兩個方法分別用於重載加號以及減號,那麼兩個向量相加,就表示它們的x值及y值相加,當兩個向量相減,就表示它們的x值及y值相減。

//定義一個向量類
class Vector { final int x; final int y; const Vector(this.x, this.y); //重載加號 + (a + b)
  Vector operator +(Vector v) { retrun new Vector(x + v.x, y + v.y); } //重載減號 - (a - b)
  Vector operator -(Vector v) { retrun new Vector(x - v.x, y - v.y); } } main() { //實例化兩個向量
  final v = new Vector(2, 3); final w = new Vector(2, 2); final r1 = v + w; print('r1.x=' + r1.x.toString() + ' r1.y=' + r1.y.toString()); final r2 = v - w; print('r2.x=' + r2.x.toString() + ' r2.y=' + r2.y.toString()); } //上面輸出結果爲: //flutter: r1.x=4 r1.y=5 //2+2 2+3 //flutter: r2.x=0 r1.y=1 //2-2 3-2

(5)繼承類

繼承是面向對象編程技術的一塊基石,由於它容許建立分等級層次的類。繼承就是子類繼承父類的特徵和行爲,使得子類對象(實例)具備父類的實例域和方法;或子類從父類繼承方法,使得子類具備父類相同的行爲。Dart裏使用extends關鍵字來建立一個子類,super關鍵字來制定父類。

Dart中的類的繼承:
①子類使用extends關鍵詞來繼承父類
②子類會繼承父類裏面可見的屬性和方法,可是不會繼承構造函數
③子類能複寫父類的方法 getter 和 setter


例子1:子類繼承父類

class User{ String name = "張三"; num age = 20; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } } class Web extends User{ //Web類繼承User類裏面可見的屬性和方法
 } void main(){ Web w = new Web(); print(w.name); //張三
  w.printInfo(); //張三----20
}

例子2:實例化子類的時候給父類傳參,經過super來實現

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } } class Web extends User{ //Web類的構造函數:初始化列表
  Web(String name, num age) : super(name, age){ //執行子類的構造函數以前,把子類裏面的傳過來的參數賦值給父類

}
} void main(){ Web w new Web("張三",12); w.printInfo(); //張三----12 }

例子3:子類裏能夠定義本身的屬性和方法

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } } class Web extends User{ String sex; //Web類的構造函數:初始化列表
 Web(String name, num age, String sex) : super(name, age){ this.sex = sex; } run(){ print(("${this.name}----${this.age}----${this.sex}"); } } void main(){ Web w = new Web("張三",12,""); w.printInfo(); //張三----12
  w.run(); //張三----12----男
}

例子4:給父類的命名構造函數傳參

class User{ String name; num age; User(this.name,this.age); User.xxx(this.name,this.age); //命名構造函數
  void printInfo(){ print("${this.name}----${this.age}"); } } class Web extends User{ String sex; //Web類的構造函數:初始化列表
  Web(String name, num age, String sex) : super.xxx(name, age){ //給命名的構造函數傳參
    this.sex = sex; } run(){ print(("${this.name}----${this.age}----${this.sex}"); } } void main(){ Web w = new Web("張三",12,""); w.printInfo(); //張三----12
  w.run(); //張三----12----男
}

例子5:子類裏直接調用父類方法

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } work(){ print("${this.name}在公做..."); } } class Web extends User{ Web(String name, num age) : super(name, age){ } run(){ print(("run"); super.work(); //子類直接調用父類的方法 也能夠經過this
 } } void main(){ Web w = new Web("李四",20); w.run(); //run //李四在公做...
}

例子6:子類裏複寫父類的方法

class User{ String name; num age; User(this.name,this.age); void printInfo(){ print("${this.name}----${this.age}"); } work(){ print("${this.name}在公做..."); } } class Web extends User{ Web(String name, num age) : super(name, age){ } run(){ print(("run"); } //複寫父類的方法 和父類的方法名字同樣
  @override //複寫父類方法的時候建議寫上
  void printInfo(){ print("姓名:${this.name}----年齡:${this.age}"); } @override work(){ print("${this.name}的工做是寫代碼"); } } void main(){ Web w = new Web("李四",20); w.printInfo(); //姓名:李四----年齡:20
  w.work(); //李四的工做是寫代碼
}

例子:定義一個動物類,動物具備吃和跑兩種能力。再定義一我的類,人類是屬於動物類的,人類不只會吃和會跑,還會說、會學習。因此人類至關於動物類的一個擴展。具體代碼:

//動物類
class Animal { //動物會吃
  void eat() { print('動物會吃'); } //動物會跑
  void run() { print('動物會跑'); } } //人類
class Person extends Animal{ //人類會說
  void say() { print('人類會說'); } //人類會學習
  void study() { print('人類會學習'); } } main() { print('實例化一個動物類'); var animal = new Animal(); animal.eat(); animal.run(); print('實例化一我的類'); var person = new Person(); person.eat(); person.run(); person.say(); person.study(); } //輸出結果: //flutter:實例化一個動物類 //flutter:動物會吃 //flutter:動物會跑 //flutter:實例化一我的類 //flutter:動物會吃 //flutter:動物會跑 //flutter:人類會說 //flutter:人類會學習

(6)抽象類

抽象類相似於Java語言中的接口。抽象類裏不具體實現方法,只是寫好定義接口,具體實現留着調用的人去實現。

Dart中的抽象類:Dart抽象類主要用於定義標準,子類能夠繼承抽象類,也能夠實現抽象類接口。

①.抽象類經過abstract關鍵字來定義
②.Dart中的抽象方法不能用abstract聲明,Dart中沒有方法體的方法咱們稱爲抽象方法
③.若是子類繼承抽象類,必須實現裏面的抽象方法
④.若是把抽象類當作接口實現的話,必須得實現抽象類裏面定義的全部屬性和方法。
⑤.抽象類不能被實例化,只有繼承它的子類能夠



例子:定義一個Animal類,要求它的子類必須包含eat方法

abstract class Animal{ //abstract定義抽象類
  eat(); //抽象方法 沒有方法體的方法咱們稱爲抽象方法
  run(); //抽象方法
  printInfo(){ //非抽象方法 普通方法
    print("我是一個抽象類裏面的普通方法"); } } class Dog extends Animal{ //若是子類繼承抽象類,必須實現裏面的抽象方法
 @override eat(){ print("小狗在吃骨頭"); } @override run(){ print("小狗在跑"); } } class Cat extends Animal{ //若是子類繼承抽象類,必須實現裏面的抽象方法
 @override eat(){ print("小貓在吃魚"); } @override run(){ print("小貓在跑"); } } void main(){ Dog dog = new Dog(); dog.eat(); //小狗在吃骨頭
  Cat cat = new Cat(); cat.eat(); //小貓在吃魚
  var a = new Animal(); //報錯,Animal是抽象類無法直接被實例化 //抽象類不能被實例化,只有繼承它的子類能夠
  cat.printInfo(); //我是一個抽象類裏面的普通方法
}

例子:定義一個抽象類叫DateBaseOperate,裏面定義4個數據庫經常使用的操做方法「增刪改查」。再定義一個類命名爲DateBaseOperateImpl繼承自DateBaseOperate用來實現抽象類裏的方法。代碼以下:

//數據庫操做抽象類
abstract class DateBaseOperate { void insert();  //定義插入的方法
  void delect();  //定義刪除的方法
  void update();  //定義更新的方法
  void query();   //定義查詢的方法
} //數據庫操做實現類
class DateBaseOperateImpl extends DateBaseOperate { //實現了插入的方法
  void insert() { print('實現了插入的方法'); } //實現了刪除的方法
  void delect() { print('實現了刪除的方法'); } //實現了更新的方法
  void update() { print('實現了更新的方法'); } //實現了查詢的方法
  void query() { print('實現了查詢的方法'); } } main(){ var db = new DateBaseOperateImpl(); db.insert(); db.select(); db.update(); db.query(); } //輸出結果爲: //flutter:實現了插入的方法 //flutter:實現了刪除的方法 //flutter:實現了更新的方法 //flutter:實現了查詢的方法

(7)接口:

首先,dart的接口沒有interface關鍵字定義接口,而是普通類或抽象類均可以做爲接口被實現。
一樣使用implements關鍵字進行實現接口。
可是dart的接口有點奇怪,若是實現的類是普通類,會將普通類和抽象類中的屬性的方法所有須要複寫一遍。
而由於抽象類能夠定義抽象方法,普通類不能夠,因此通常若是要實現像Java接口那樣的方式,通常會使用抽象類。
建議使用抽象類定義接口。



例子:定義一個DB庫,支持mysql、mssql、mongodb,這三個類裏面都有一樣的方法。

abstract class Db{ //abstract定義抽象類 當作接口 接口就是約定、規範
  String url; //數據庫的連接地址
 add(String data); edit(); delete(); } class Mysql implements Db{ //implements來實現接口Db
 @override String url; Mysql(this.url); @override add(String data){ print("這是mysql的add方法" + data); } @override edit(){ } @override delete(){ } } class Mssql implements Db{ //implements來實現接口Db
 @override String url; @override add(String data){ print("這是mssql的add方法" + data); } @override edit(){ } @override delete(){ } } void main(){ Mysql mysql = new Mysql("http://xxx"); mysql.add("12345"); //這是mysql的add方法12345
}

能夠把以上代碼分離成3個dart文件,方便想用誰就能夠引用誰。

Db.dart

abstract class Db{ //abstract定義抽象類 當作接口 接口就是約定、規範
  String url; //數據庫的連接地址
 add(String data); edit(); delete(); }

Mysql.dart

impor "Db.dart"; class Mysql implements Db{ //implements來實現接口Db
 @override String url; Mysql(this.url); @override add(String data){ print("這是mysql的add方法" + data); } @override edit(){ } @override delete(){ } } 

Mssql.dart

import "Db.dart"; class Mssql implements Db{ //implements來實現接口Db
 @override String url;
Mssql(this.url); @override add(String data){ print(
"這是mssql的add方法" + data); } @override edit(){ } @override delete(){ } }

使用那個就引用:

import "Mysql.dart"; import "Mssql.dart"; void main(){ Mysql mysql = new Mysql("http://xxx"); mysql.add("12345"); //這是mysql的add方法12345
  Mssql mssql = new Mssql(); mssql.url = "http://xxx"; mssql.add("增長的數據"); //這是這是mssql的add方法增長的數據
}

extends抽象類和implements的區別:
①.若是要複用抽象類裏面的方法,而且要用抽象方法約束子類的話,咱們就用extends繼承抽象類
②.若是隻是把抽象類當作標準的話,咱們就用implements實現抽象類。

例子:Dart中一個類實現多個接口:

abstract class A{ //abstract定義抽象類A 當作接口
 String name; printA(); //抽象方法
} abstract class B{ //abstract定義抽象類B 當作接口
      printB(); //抽象方法
} class C implements A,B{ //implements來實現接口A,B,實現全部屬性和方法
 @override String name; @override printA(){ print("printA"); } @override printB(){ } } void main(){ C c = new C(); //實例化C
      c.printA(); //printA
}

(8)Dart中的多態:

容許將子類類型的指針賦值給父類類型的指針,同一個函數調用會有不一樣的執行效果。
子類的實例賦值給父類的引用。
多態就是父類定義一個方法不去實現,讓繼承它的子類去實現,每一個子類有不一樣的表現。

例子:這個就是多態

abstract class Animal{ //abstract定義抽象類
  eat(); //抽象方法 父類定義一個方法不去實現,讓繼承它的子類去實現,每一個子類有不一樣的表現。
} class Dog extends Animal{ //若是子類繼承抽象類,必須實現裏面的抽象方法
 @override eat(){ print("小狗在吃骨頭"); } } class Cat extends Animal{ //若是子類繼承抽象類,必須實現裏面的抽象方法
 @override eat(){ print("小貓在吃魚"); } } void main(){ Dog dog = new Dog(); dog.eat(); //小狗在吃骨頭
  Cat cat = new Cat(); cat.eat(); //小貓在吃魚
}

例子:也是多態,若是子類只能運行父類裏定義的方法

abstract class Animal{ //abstract定義抽象類
  eat(); //抽象方法 父類定義一個方法不去實現,讓繼承它的子類去實現,每一個子類有不一樣的表現。
} class Dog extends Animal{ //若是子類繼承抽象類,必須實現裏面的抽象方法
 @override eat(){ print("小狗在吃骨頭"); } run(){ print("run"); } } class Cat extends Animal{ //若是子類繼承抽象類,必須實現裏面的抽象方法
 @override eat(){ print("小貓在吃魚"); } run(){ print("run"); } } void main(){ Animal dog = new Dog(); //表示把子類的實例賦值給了父類的一個引用,不能在調用run方法,只能調用父類定義的方法
  dog.eat(); //小狗在吃骨頭
  Animal cat = new Cat(); cat.eat(); //小貓在吃魚
}

(9)枚舉類型

枚舉類型是一種特殊的類,一般用來表示相同類型的一組常量值。每一個枚舉類型都用於一個index的getter,用來標記元素的元素位置。第一個枚舉元素的索引是0.

enum Color { red, green, blue }

獲取枚舉類中全部的值,使用value經常使用:

List<Color> colors = Color.values;

由於枚舉類型裏面的每一個元素都是相同類型,可使用switch語句來針對不一樣的值作不一樣的處理,示例代碼以下:

enum Color { red, green, blue } //定義一個顏色變量 默認值爲藍色
Color aColor = Color.blue; switch (aColor) { case Color.red: print('紅色'); break; case Color.green: print('綠色'); break; default: //默認顏色
    pring(aColor); //Color.blue
}

(10)Mixins:中文意思是混入,就是在類中混入其餘功能,實現相似多繼承的功能。

Mixins(混入功能)至關於多繼承,也就是說能夠繼承多個類。使用with關鍵字來實現Mixins的功能。

由於mixins使用的條件,隨着Dart版本一直在變,這裏講的是Dart2.x中使用mixins的條件:
①.做爲mixins的類只能繼承自Object,不能繼承其餘的
②.做爲mixins的類不能有構造函數
③.一個類能夠mixins多個mixins類
④.mixins毫不是繼承,也不是接口,而是一種全新的特性



例子1:

class A{ String info = "this is A"; void printA(){ print("A"); } } class B{ void printB(){ print("B"); } } class C with A,B { //混入 C類繼承A類和B類的屬性和方法
 } void main(){ var c = new C(); c.printA(); //A
    c.printB(); //B
    print(c.info); //this is A
}

例子2:

class User{ String name; num age; User(this.name,this.age);//構造函數
 printInfo(){ print("${this.name}----${this.age}"); } void run(){ print("User run"); } } class A{ String info = "this is A"; void printA(){ print("A"); } void run(){ print("A run"); } } class B{ void printB(){ print("B"); } void run(){ print("B run"); } } class C extends User with A,B { //即繼承User又混入A,B
      C(String name, num age):super(name,age); //父類裏有構造函數並傳參的話,子類也要寫構造函數
 } void main(){ var c = new C("張三",20); c.printInfo(); //張三----20
      c.run(); //B run //一樣的run方法,後面的把前面的覆蓋了
}

示例代碼以下:

class S { a() {print('S.a');} } class A { a() {print('A.a');} b() {print('A.b');} } class T = A with S; main(List<String> args) { T t = new T(); t.a(); t.b(); } //上面代碼從結果來看T具備了S及A兩個類的方法 //S.a //A.b

Mixins的實例類型是其超類的子類型:

class A{ String info = "this is A"; void printA(){ print("A"); } } class B{ void printB(){ print("B"); } } class C with A,B { } void main(){ var c = new C(); print(c is A); //true A和B就是C的超類
    print(c is B); //true
}

九、泛型:就是解決類、接口、方法的複用性,以及對不特定數據類型的支持(類型校驗)

泛型一般是爲了類型安全而設計的,適當地指定泛型類型會生成更好的代碼,可使用泛型來減小代碼重複。Dart中使用<T>的方式來定義泛型。

例子:傳入什麼類型,返回什麼類型的數據

T getData<T>(T value){ //T表明泛型,能夠是任意字母
    return value; } //也能夠這樣寫,對傳入參數進行校驗,不對返回參數校驗
getData<T>(T value){ return value; } void main(){ print(getData<int>(12)); //12
}

例如,若是想要List只包含字符串,能夠將其聲明爲list<String>。以下所示:

var names = new List<String>(); names.addAll(['張三', '李四', '王五']);

(1)用於集合類型

泛型用於List和Map類型參數化:List:<type>      Map:<keyType, valueType>

例子:

List list = new List<String>(); list.add('你好'); list.add('你們好'); print(list); //[你好, 你們好]
 List list2 = new List<int>(); list2.add(11); list2.add(22); print(list2); //[11, 22]

例子:

var names = <String>['張三', '李四', '王五']; var weeks = <String, String>{ 'Monday' : '星期一', 'Tuesday' : '星期二', 'Wednesday' : '星期三', 'Thursday' : '星期四', 'Friday' : '星期五', 'Saturday' : '星期六', 'Sunday' : '星期日', };

例子:把下面類轉換成泛型類,要求List裏面能夠增長int類型的數據,也能夠增長String類型的數據。

class PrintClasee<T>{ List list = new List<T>(); void add(T value){ this.list.add(value); } void printInfo(){ for(var i = 0; i < this.list.length; i++){ print(this.list[i]); } } } void main(){ PrintClasee p = new PrintClasee<String>(); p.add("你好"); p.add("你們好"); p.printInfo(); //你好 //你們好
 PrintClasee p2 = new PrintClasee<int>(); p2.add(12); p2.add(33); p2.printInfo(); //12 //33
}

(2)在構造函數中參數化

Map類型的例子以下:

var users = new Map<String, String>();

(3)泛型接口

實現數據緩存的功能:有文件緩存和內存緩存,文件緩存和內存緩存按照接口約束實現
①.定義一個泛型接口,約束實現它的子類必須由getByKey(key)和setByKey(key,value)
②.要求setByKey時候的value的類型和實例化子類時候指定的類型一致

abstract class Cache<T>{ getByKey(String key); void setByKey(String key, T value); } class FileCache<T> implements Cache<T>{ //文件緩存
 @override getByKey(String key){ return null } @override void setByKey(String key, T value){ print("我是文件緩存 把key=${key} vlaue=${value} -寫入文件中"); } } class MemoryCache<T> implements Cache<T>{ //內存緩存
 @override getByKey(String key){ return null } @override void setByKey(String key, T value){ print("我是內存緩存 把key=${key} vlaue=${value} -寫入內存中"); } } void main(){ MemoryCache m = new MemoryCache<String>(); m.setByKey("index","首頁數據"); //我是內存緩存 把key=index vlaue=首頁數據 -寫入內存中
 MemoryCache map = new MemoryCache<Map>(); map.setByKey("index",{"name":"張三","age":20}); //我是內存緩存 把key=index vlaue={"name":"張三","age":20} -寫入內存中
}

十、庫的使用

Dart中的庫主要有三種:
①.咱們自定義的庫,好比import "lib/xx.dart";
②.系統內置庫,好比import "dart:io";
③.Pub包管理系統中的庫,好比import "package:dio/dio.dart"; (須要在pubspec.yaml文件裏添加依賴)


(1)引用庫

經過import語句在一個庫中引用另外一個庫的文件。須要注意如下事項:

  • 在import語句後面須要接上庫文件的路徑。
  • 對Dart語言提供的庫文件使用dart:xx格式。
  • 第三方的庫文件使用package:xx格式。

import例子:

import 'dart:io'; import 'package:mylib/mylib.dart'; import 'package:utils/utils.dart';

(2)指定一個庫的前綴

當引用的庫擁有相互衝突的名字,能夠爲其中一個或幾個指定不同的前綴。這與命名空間的概念比較接近。示例代碼以下:

import 'package:lib1/lib1.dart'; import 'package:lib2/lib2.dart' as lib2; //...
Element element1 = new Element();  //使用lib1中的Element
lib2.Element element2 = new lib2.Element();  //使用lib2中的Element

lib1/lib1.dart及lib2/lib2.dart裏都有Element類,若是直接引用就不知道具體引用那個Element類,因此代碼中把lib2/lib2.dart指定成lib2,這樣使用lib.Element就不會發生衝突。

(3)引用庫的一部分

若是隻須要使用庫的一部份內容,能夠有選擇的引用,有以下關鍵字:

  • show關鍵字:只引用一點。
  • hide關鍵字:除此以外都引用。

示例代碼以下:

//導入foo
import 'package:lib1/lib1.dart' show foo; //除了foo導入其餘全部內容
import 'package:lib1/lib1.dart' hide foo;

十一、異步支持

Dart語言是目前少數幾個支持異步操做的語言。通常使用async函數和await表達式實現異步操做。

Dart庫提供asynchronous功能,該功能提供接口來進行耗費時間的操做,好比文件讀寫、網絡請求。該功能返回Future或Stream對象。

能夠經過以下的方式來獲取asynchronous功能返回的Future對象的值:

  • 使用async函數和await表達式。
  • 使用Future功能提供的API。

能夠經過以下的方式來獲取asynchronous功能返回的Stream對象的值:

  • 使用async和一個異步的循環(await for)。
  • 使用Stream的相關API。

下面的例子代碼使用了async或await異步處理,雖然代碼看起來像是同步處理的:await readFile()

必須在一個使用了async關鍵字標記後的函數中使用await表達式:

fileOperate () async { //讀取文件
  var file = await readFile(); //其餘處理
}

十二、元數據 

使用元數據給代碼添加更多的信息。元數據是以@開始的修飾符,在@後面接着編譯時的常量或調用一個常量構造函數。目前Dart語言提供三個@修飾符:

(1)@deprecated被棄用的

(2)@override重寫

(3)@proxy代理

使用@voerride修飾符能夠重寫父類方法。改造以前寫的例子,人類重寫eat方法,代碼以下:

//動物類
class Animal { //動物會吃
  void eat(){ print('動物會吃'); } //動物會跑
  void run(){ print('動物會跑'); } } //人類
class Person extends Animal { //人類會說
  void say(){ print('人類會說'); } //人類會學習
  void study(){ print('人類會學習);
 } @override //人類也會吃
  void eat(){ print('人類也會吃'); } } main() { print('實例化一個動物類'); var animal = new Animal(); animal.eat(); animal.run(); print('實例化一我的類'); var person = new Person(); person.eat(); person.run(); person.say(); person.study(); } //輸出結果是 //flutter:實例化一個動物類 //flutter:動物會吃 //flutter:動物會跑 //flutter:實例化一我的類 //flutter:人類也會吃 //flutter:動物會跑 //flutter:人類會說 //flutter:人類會學習

元數據能夠修飾library(庫)、class(類)、typedef(類型定義)、type parameter(類型參數)、constructor(構造函數)、factory(工廠函數)、function(函數)、field(做用域)、parameter(參數)、variable declaration(變量聲明)。

1三、註釋

 Dart支持三種註釋類型:單行註釋、多行註釋、文檔註釋。

(1)單行註釋:以//開頭。從//開始到一行結束的全部內容都會被Dart編譯器忽略。

(2)多行註釋:以/*開頭,以*/結束,之間的全部內容都會被Dart編譯器忽略。

(3)文檔註釋:以/**或///開頭。

相關文章
相關標籤/搜索