1.Dart語言的優(yōu)勢
1)Dart 有兩種運行方式日杈,靜態(tài)編譯(AOT Ahead Of Time)和動態(tài)解釋(JIT Just In Time)。
AOT:靜態(tài)編譯的程序在執(zhí)行前全部被翻譯為機器碼设哗。在Flutter 的Release模式下使用,閉了所有斷言疮绷,盡可能多地去掉了調試信息卿堂,關閉了所有調試工具。為快速啟動髓废,快速執(zhí)行巷懈,包大小做了優(yōu)化。禁止了所有調試輔助手段慌洪,服務擴展顶燕。
JIT:動態(tài)解釋凑保,就是邊翻譯邊運行,每次改都不需要再編譯成字節(jié)碼,節(jié)省了大量時間,縮短產品的開發(fā)周期敛滋。對應Flutter的Debug模式,此模式下打開了斷言隙疚,包括所有的調試信息,服務擴展和Observatory等調試輔助,支持廣受歡迎的亞秒級有狀態(tài)的hot reload。
2)易于移植婚苹,Dart可編譯成ARM和X86代碼,這樣Dart移動應用程序可以在iOS鸵膏、Android和其他地方運行租副。
3)Dart可以在沒有鎖的情況下進行對象分配和垃圾回收。像JavaScript一樣较性,Dart避免了搶占式調度和共享內存,大多數支持并發(fā)執(zhí)行線程的計算機語言(Java结胀、Kotlin赞咙、Swift)都使用搶占式來切換線程,搶占就會產生競態(tài)條件糟港,競態(tài)條件很有可能導致嚴重錯誤攀操,如應用程序崩潰導致數據丟失等等,一般解決競態(tài)條件使用鎖來保護秸抚,但是鎖本身可能導致卡頓速和,也有可能產生死鎖,而Dart針對這個問題剥汤,采取了isolate方法來解決颠放,Dart中的線程稱為isolate,不共享內存吭敢。那么Dart是單線程的碰凶,意味根本不允許搶占。單線程有助于開發(fā)者確保關鍵功能(動畫和轉場)完成而無需搶占鹿驼。 Flutter應用程序被編譯為本地代碼欲低,因此它們不需要再領域之間建立緩慢的橋梁,所以啟動速度快得多畜晰。
2.Dart語言的特性
1)在Dart中砾莱,一切都是對象,每個對象都是一個類的實例凄鼻,所有對象都繼承自Object腊瑟。
2)沒有賦初值的變量都會有默認值null聚假。
2)Dart不具備關鍵字public、protected扫步、private魔策。如果一個標識符以下劃線_開始,那么它和它的庫都是私有的河胎。
3)Dart支持泛型類型闯袒,如List<int>(整數列表)或List<dynamic>(任何類型的對象列表)。
4)Dart是強類型語言游岳,但可以用var或者dynamic來聲明一個變量政敢,Dart會自動推斷其數據類型,dynamic類似C#胚迫。
5)Dart中的類和接口都是統(tǒng)一的喷户,類即是接口,你可以繼承一個類访锻,也可以實現一個類褪尝,自然也包含了良好的面向對象和并發(fā)編程的支持。
6)Dart支持頂級方法期犬,如main方法河哑,同時還支持在類中定義函數(靜態(tài)函數和實例函數),還可以在方法中定義方法龟虎,Dart支持頂層變量璃谨,也支持類變量或對象變量。
3.Dart 語法
1)注釋
// 這是注釋符號鲤妥,還可以用/*...*/這是很多語言的注釋符號
2)數據類型
- num:包含兩種子類型佳吞,int和double類型。使用num聲明的變量棉安,可以在這兩種子類型之間隨意的轉換底扳,但使用int或者double明確的聲明,那就不能轉換了。
//整形垂券,其取值通常位于-2的53次方到2的53之間花盐。
num x = 777;
//浮點數 64位
x = 777.7;
int y = 777;
y = 777.7; //這一行編譯器會報錯,因為將int型的數據轉為double型
double n = 77,7;
d = 77; //這個地方會報錯菇爪,因為將double型的數據轉為int型
- String:字符串是UTF-16編碼的字符序列算芯,可以使用單引號或者雙引號來創(chuàng)建字符串。單引號和雙引號之間可以相互嵌套凳宙。
字符串嵌套:
String m_str1 = '單引號中的"雙引號"字符串';
String m_str2 = "雙引號中的'單引號'字符串";
print(m_str1); //輸出:單引號中的"雙引號"字符串
print(m_str2); //輸出:雙引號中的'單引號'字符串
字符串拼接:
// 使用空格拼接熙揍,多個空格也是可以地
String m_str1 = '單引號字符串' '拼接' '---';
print(m_str1); //輸出:單引號字符串拼接---
// $可以獲取字符串的內容,用${表達式}可以將表達式的值放入字符串中氏涩,使用${表達式}也可以使用字符串拼接
bool flag = true;
String m_str1 = "字符串";
print("看看這個值:${m_str1} ""看看這個值flag:${flag}");
//輸出:看看這個值:字符串 看看這個值flag:true
//使用$+字符串
String name = "knight";
print("$name" + "CTO"); //輸出:knightCTO届囚;
- bool:布爾值只有 true 和 false,默認值是null有梆。
當Dart需要一個布爾值,只有true對象才被認為是true意系,所有其他值都是false泥耀。
String name ="knight";
//報錯 因為name不是bool類型
if(name){
print(name);
}
- enum:枚舉
枚舉類型是一種特殊的類,通常用來表示相同類型的一組常量蛔添。使用關鍵字enum定義枚舉痰催。
枚舉類型不能定義在類中,枚舉的每一個值都有一個index屬性迎瞧,index從0開始計數夸溶。枚舉不能被繼承,不能創(chuàng)建實例凶硅。
enum Animal {
cat,
dog,
bird
}
- list:在Dart中數組就是List對象缝裁。
list 創(chuàng)建:
//創(chuàng)建一個int類型的list 并賦值為0,1足绅,2捷绑,3,4
List list = [0,1,2,3,4];
//使用構建的方式創(chuàng)建list
List list1 = new List();
//創(chuàng)建一個常量的List氢妈,不可以改變的List
List list2 = const[0,1,2,3];
//增加泛型
List list3 = new List<String>();
//創(chuàng)建固定的長度的數組列表胎食,不能移除或者增加
List list4 = new List(5);
//創(chuàng)建包含所有以下元素的可改變的長度列表
List list5 = new List.from([0,1,2,3]);
list 操作:
//在列表中存放不同類型的對象
List list = [1,2,3,false,"Kinght"];
print(list); //輸出:[1, 2, 3, false, Kinght]
//在列表中添加元素
list.add(7);
print(list); //輸出:[1, 2, 3, false, Kinght, 7]
//修改列表下標為1的值
list[1] = "paul";
print(list); //輸出:[1, paul, 3, false, Kinght, 7]
//移除列表的指定值得的元素
list.remove("paul");
print(list); //輸出:[1, 3, false, Kinght, 7]
//移除列表指定下標下的元素
list.removeAt(0);
print(list); //輸出:[3, false, Kinght, 7]
//獲取列表的長度
print(list.length); //輸出:4
//向列表中的指定位置添加元素 在第0的位置上插入Android
list.insert(0, "Android");
print(list); //輸出:[Android, 3, false, Kinght, 7]
//判斷數組中是否有某元素
print(list.indexOf("Android")); //這里存在,輸出對應的下標允懂,如果沒有則輸出-1
//排序
List list1 = [3,1,2,6,7];
// 根據語法提示: List.sort([(int, int) → int compare]) → void
list1.sort((a,b) => a.compareTo(b));
print(list1); //輸出:[1, 2, 3, 6, 7]
- Map:一個鍵值對相關的對象,鍵和值可以是任何類型的對象衩匣。當Map的Key沒有指定類型時蕾总,Key類型不一致也不會報錯。但每個鍵只出現一次琅捏,而一個值則可以出現多次生百,而且value可以為空字符串或者為null。
Map 創(chuàng)建:
//1.通過構建器來創(chuàng)建Map
Map map1 = new Map();
//添加值 賦值
map1["one"] = 'Android';
map1["two"] = 'IOS';
map1["three"] = 'Flutter';
print(map1); //輸出:{one: Android, two: IOS, three: Flutter}
//2.通過復制的形式
Map map2 = Map.of(map1);
print(map2); //輸出:{one: Android, two: IOS, three: Flutter}
//3.跟上面形式一樣 Object.fromEntries() 函數傳入一個鍵值對的列表柄延,并返回一個帶有這些鍵值對的新對象蚀浆。
// 這個迭代參數應該是一個能夠實現@iterator方法的的對象,返回一個迭代器對象搜吧。它
// 生成一個具有兩個元素的類似數組的對象市俊,第一個元素是將用作屬性鍵的值,第二個元素是與該屬性鍵關聯的值滤奈。
Map map3 = Map.fromEntries(map1.entries);
print(map3);
//4.直接聲明摆昧,直接賦值key為String類型的map
Map map4 = {'one':'Android',
'two':'IOS',
'three':'Flutter'};
print(map4); //輸出:{one: Android, two: IOS, three: Flutter}
//5.創(chuàng)建一個空的Map
Map map5 = Map.identity();
print(map5); //輸出:{}
//6.創(chuàng)建不可變的Map
Map map6 = const {'one':'Android','two':'IOS','three':'flutter'};
print(map6); //輸出:{one: Android, two: IOS, three: flutter}
//7.在目標的map6創(chuàng)建(復制)新的不可修改map7
Map map7 = Map.unmodifiable(map6);
print(map7); //輸出:{one: Android, two: IOS, three: flutter}
//8.創(chuàng)建key為int值得map
Map map8 = {1:'Android',
2:'IOS',
3:'Flutter'};
print(map8); //輸出:{1: Android, 2: IOS, 3: Flutter}
//9.根據list所提供的key value來創(chuàng)建map
List<String> keys = ['one','two'];
List<String> values = ['Android','IOS'];
Map map9 = Map.fromIterables(keys, values);
print(map9); //輸出:{one: Android, two: IOS}
//通過構建器來創(chuàng)建Map
Map map10 = new Map();
//添加值 賦值 賦值不同類型的Map
map10["one"] = 'Android';
map10["two"] = 'IOS';
map10["three"] = 'Flutter';
map10[4] = 'RN';
print(map10); //輸出:{one: Android, two: IOS, three: Flutter, 4: RN}
Map 操作:
//創(chuàng)建Map key是int類型,value是String類型
var map1 = new Map<int,String>();
//對Map第一個位置賦值蜒程,中括號是key
map1[0] = 'Android';
//對Map第二個位置賦值
map1[1] = 'IOS';
//對Map第三個值賦值
map1[2] = 'flutter';
//對Map賦空值
map1[3] = null;
//因為Map中的鍵值是唯一的绅你,當第二次輸入的key如果存在伺帘,Value會覆蓋之前
map1[2] = 'RN';
print(map1); //{0: Android, 1: IOS, 2: RN, 3: null}
//獲取Map的長度
print(map1.length); //輸出:4
//判斷Map是否為空
print(map1.isNotEmpty); //輸出結果:true
//判斷Map是否不為空
print(map1.isEmpty); //輸出結果:false
//檢索Map是否含有某個Key
print(map1.containsKey(1)); //輸出:true
//檢索Map是否包含某個Value
print(map1.containsValue('Android')); //輸出:true
//刪除某個鍵值對
map1.remove(0);
print(map1); //輸出:{1: IOS, 2: RN, 3: null}
//獲取所有的key
print(map1.keys); //輸出:(1, 2, 3)
//獲取所有的values
print(map1.values); //輸出:(IOS, RN, null)
//循環(huán)打印
/*
key:1, value:IOS
key:2, value:RN
key:3, value:null
*/
map1.forEach((key,value) {
print("key:${key}, value:${value}");
});
- var:它僅僅只是一個語法, var本身并不是一種類型忌锯。var聲明的變量在賦值的那一刻伪嫁,就已經決定了它是什么類型。
// 編譯報錯
var a = 1;
a = "Test";
- object :能夠表示任意類型偶垮。因為所有的類型都派生自object张咳。
object a = 1;
a = "Test";
- dynamic:也可以表示任意類型。但確定具體類型是在運行時针史。
// 下面代碼能夠通過編譯晶伦,但是會在運行時報錯。
dynamic a = "test";
a++;
- final:修飾的變量啄枕,必須在定義時將其初始化婚陪,其值在初始化后不可改變。無法在編譯時(運行之前)知道這個變量的值频祝。
final name = 'Bob';
name = 'job';
//運行出錯泌参,因為final修飾的變量不能調用其setter方法,即:不能設值
final baz = [1];
// baz=[1,2,3,4]; //出錯 此調用修改了變量的實例 即:[1] 和[1,2,3,4]是不同的對象
baz[0]=2; //正常執(zhí)行常空,只修改了變量引用對象的成員變量的值
print(baz);
- const:用來定義常量,只能被設一次值沽一,在聲明處賦值,且值必須為編譯時常量漓糙。與final的區(qū)別是const所修飾的是編譯時常量铣缠,我們在編譯時就已經知道了它的值。
// 定義常量值
const bar = 1000000;
// bar =13;
// 出現異常昆禽,const修飾的變量不能調用setter方法蝗蛙,即:不能設值,只能在聲明處設值
const atm = 1.01325 * bar;
// 值的表達式中的變量必須是編譯時常量(bar);
// 修飾常量值
var foo = const [];
foo = [1,2,1];
/*此部分代碼的重點在于var foo , 一個正常變量可以隨意賦值或更改醉鳖,重點不在const [],
所以不要糾結const []是不可變的捡硅。[]和[1,2,1]是不同的對象*/
print(foo);
3)運算操作符
運算符:+、-盗棵、*壮韭、/、~/纹因、%
常用屬性:isNaN喷屋、isEven、isOdd
常用方法:abs()瞭恰、round()逼蒙、floor()、ceil()、toInt()是牢、toDouble()
級聯操作符:..
int i =7;
double d = 10.1;
print(i / d); //0.6930693069306931
print(i ~/ d); //0 這個操作是取整 就是得出商
print(i.isOdd); // 判斷是奇數
print(i.isEven); // 判斷是偶數
//求絕對值
var x5 = (-7).abs();
print(x5 == 7);
//四舍五入1
var x6 = (7.7).round();
print(x6); //輸出8
//求小于它的最大整數
var x8 = (7.7).floor();
print(x8); //輸出7
//求大于它的最小整數
var x9 = (7.7).ceil();
print(x9); //輸出8
級聯操作符:(..)可以在同一對象上連續(xù)調用多個函數以及訪問成員變量僵井。使用級聯操作符可以避免創(chuàng)建臨時變量,并
且寫出來的代碼看起來更加流暢驳棱。
querySelector('#button') // Get an object.
..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
相當于:
var button = querySelector('#button');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
注意:下面代碼是不合法
var sb = new StringBuffer();
sb.write('foo')..write('bar');
sb.write函數返回一個void批什,無法再void上使用級聯操作符。注意級聯語法不是操作符社搅,只是語法驻债!
4.流程控制
1) if else
if (isRaining()) {//條件語句
you.bringRainCoat();//內容體
} else if (isSnowing()) {//條件語句
you.wearJacket();//內容體
} else {
car.putTopDown();//內容體
}
2)for循環(huán)
var message = new StringBuffer("Dart is fun");
for (var i = 0; i < 5; i++) {
message.write('!');
}
//使用foreach循環(huán) list 和 Set都可以用這種方式
List numbers = [1,2,3,4,5,6,7,8,9,10];
numbers.foreach((number)=> print(number));
//使用for in循環(huán)形葬,一般List和Set都是用這種方式
List numbers = [1,2,3,4,5,6,7,8,9合呐,10];
for(var number in numbers){
print(number);
}
3)While and do-while
//判斷條件
while (!isDone()) {
//內容
doSomething();
}
do {
printLine();//內容體
} while (!atEndOfPage());//條件判斷
4)Switch and case
var command = 'OPEN';
switch (command) {
case 'CLOSED':
executeClosed();
break;
case 'PENDING':
executePending();
break;
case 'OPEN':
executeOpen();
break;
default:
executeUnknown();
5)用break來終止循環(huán),使用continue來開始下一次循環(huán)笙以。
5.function 函數
Dart是一個真正的面向對象語言淌实,方法也是對象并且具有一種類型,Function猖腕。這意味著拆祈,方法可以賦值給變量,也可以當做其他方法的參數倘感。所有的函數都返回一個值放坏。如果沒有指定返回值,則默認把語句return null;作為函數的最后一個語句執(zhí)行老玛。
1.定義一個方法 判斷列表對應下標是否為null
bool isNoble(int atomicNumber) {
return list[atomicNumber] != null;
}
2.不指定返回值類型的函數
我們可以不指定返回值類型淤年,這樣的函數返回值默認為Object,也就是說你可以返回任意類型
isNoble(int atomicNumber) {
return list[atomicNumber] != null;
}
3.縮略寫法
對于只有一個表達式的方法蜡豹,可以選擇使用縮寫語法來定義
bool isNoble(int atomicNumber) => list[atomicNumber] != null;
=> expr是語法{return expr;}形式的縮寫互亮。=>形式也稱為胖箭頭語法。注意:在箭頭(=>)和冒號(;)之間只能使用一個表達式余素,不能使用語句。
4.必須參數和可選參數
可選參數炊昆,主要被{}或者[]指定桨吊,{}是命名參數,[]是位置參數凤巨,二者不能同時使用视乐。
在定義方法的時候,可以使用=來定義可選參數的默認值敢茁。默認值只能是編譯時常量佑淀。如果沒有提供默認值,則默認值為null彰檬。
可選命名參數方法:
void enableFlags({bool bold = false,bool hidden = false}){
}
//調用方法 沒有傳hidden的值伸刃,那默認值就是false
enableFlags(bold:true);
可選位置參數方法:
//定義一個方法 這個方法位置可選位置參數device的默認參數是carrier pigon
//也就是當調用這個方法谎砾,沒有傳這個參數時,這個參數會取默認值
String say(String from, String msg,
[String device = 'carrier pigeon', String mood]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
if (mood != null) {
result = '$result (in a $mood mood)';
}
return result;
}
//調用上面的方法
assert(say('Bob', 'Howdy') ==
'Bob says Howdy with a carrier pigeon');
List和Map 作參數
//List和Map都取了默認值
void doStuff(
{List<int> list = const [1, 2, 3],
Map<String, String> gifts = const {
'first': 'paper',
'second': 'cotton',
'third': 'leather'
}}) {
print('list: $list');
print('gifts: $gifts');
}
5.匿名函數
函數格式:
([[Type] param1[, …]]) {
codeBlock;
};
// 定義了一個參數為i(該參數沒有指定類型)的匿名函數捧颅。 list中的每個元素都會調用這個函數打印出來景图。
var list = ['張無忌', '風清揚', '張三豐', '獨孤求敗', '蕭峰'];
list.forEach((i) {
print(list.indexOf(i).toString() + ': ' + i);
});
6.閉包
個閉包是一個方法對象,不管該對象在何處被調用碉哑,該對象都可以訪問其作用域內的變量挚币,方法可以封閉定義到其作用域內的變量。
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
main() {
//相當于 add2 = (num i) => 2 + i;
var add2 = makeAdder(2);
// 相當于 add4 = (num i) => 4 + i;
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
6.Assert(斷言)
如果條件表達式結果不滿足需要扣典,則可以使用assert語句來打斷代碼的執(zhí)行妆毕。
/ 確保變量是非空值
assert(text != null);
// 確保值是小于100
assert(number < 100);
// 確保這是一個 https 地址
assert(urlString.startsWith('https'));
assert方法參數可以為任何布爾值的表達式或者方法。如果返回的值為true贮尖,斷言執(zhí)行通過笛粘,執(zhí)行結束。如果返回值為false远舅,斷言執(zhí)行失敗闰蛔,會拋出異常,斷言只有在debug模式運行有效图柏,如果生產模式運行序六,則斷言不會執(zhí)行。
7.Exceptions(異常)
1)throw
thow new FormatException('Expected at least 1 section');
// 可以拋出任意對象
throw 'Out of llamas!';
2)try catch finally
可以使用on或者catch來聲明捕獲語句蚤吹,也可以同時使用例诀。使用on來指定異常類型,使用catch來捕獲異常對象裁着。函數catch()可以帶有一個或者兩個參數繁涂,第一個參數為拋出的異常對象,第二個為堆棧信息二驰。
...
} on Exception catch (e) {
print('Exception details:\n $e');
} catch (e, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
}
finally :無論是否拋出異常扔罪,要確保某些代碼都要執(zhí)行,可以使用finally語句來實現桶雀。
try {
breedMoreLlamas();
} catch(e) {
print('Error: $e'); // 優(yōu)先處理異常
} finally {
cleanLlamaStalls(); // 然后再執(zhí)行
}
如果沒有catch語句來捕獲異常矿酵,則在執(zhí)行完finally語句后,異常被拋出了矗积。