一. Dart入口方法
每一個flutter項目的lib目錄里面都有一個main.dart。這個文件就是flutter的入口文件,其中的main方法是dart的入口方法。
runApp返回的是組件。MyApp是自定義的一個組件。在flutter里面萬物皆組件。
# void是當前函數的返回值 可以省略
void main() {//程序執行的入口函數 有且僅有一個 必須的
runApp(MyApp)
print('Hello World!')//dart通過print方法打印數據
}
//如果runApp后面只有一行代碼也可以這樣寫
void main() => runApp(MyApp());
二. Dart變量,常量和命名規則
- 變量
dart是一個強大的腳本類語言,可以不預先定義變量類型,dart會通過類型推斷 type inference(swift也是)自動判斷當前變量的類型。dart中定義變量是通過var關鍵字或者通過類型來聲明變量。
var str = '這是var變量';
String str1 = '這是類型聲明的變量';
int number = 123;
注意: var 后不要寫類型,寫了類型不要寫var 寫了會報錯 var a int = 5
-
常量
常量通過
final
或者const
修飾。差異之處:
const
修飾的常量在創建時就需要賦值(編譯時的常量)賦值后不可改變。final
不僅有const
的編譯時的常量特性,最重要的是它的運行時常量。并且final
是惰性初始化,即在運行時第一次使用前才初始化。如果是不改量的量,請使用final
或者cont
修飾它,而不是使用var
或者其他變量類型。
final name = ‘huang’;
final String rename = 'hai';
const bar = 100000;
cont double atm = 1.01325 * bar
- dart的命名規則
- 變量等名稱必須由數字、字母、下劃線和美元符號($)組成。
- 注意:標識符開頭不能是數字。
- 標識符不能使保留字或者關鍵字。
- 變量的名稱是區分大小寫的如:age和Age是不同的變量。在實際的運用中,也建議不要用一個
- 標識符(變量名稱)一定要見名思意 :變量名稱建議用名稱,方法名稱建議用動詞
三. Dart基礎數據類型
-
字符串(String)
① 字符串創建方式
通過var
關鍵字或者String
單引號、雙引號、三個單引號或者三個雙引號來包裹字符組成字符串變量或者常量。
②字符串拼接,通過+
號或者通過$加變量 $str或者${表達式}
。
對應的①
/單引號 '' 或者 雙引號 "" 來包裹字符組成字符串
String str1 = '這是字符串';
String str2 = "這是字符串";
//使用 + 鏈接兩個字符串
String str3 = str1 + str2;
print(str3);
//多行字符串使用三重單引號 '''字符串'''
//三重雙引號 """字符串"""
String str4 = """ 1111
22222
333333""";
print(str4);
//使用r前綴 可以使字符串里面的特殊字符作為普通字符串
// \n 換行符 特殊字符
String str5 = r'這是特殊字符\n現在不會換行';
String str6 = '這是特殊字符\n現在會換行';
print(str5);
print(str6);
對應的②
var str4 = str + str1;
print('$str4 ${str4.length}');
// dart判斷數據類型 is關鍵詞用來判斷數據類型
if(str4 is String){
// print()
}
-
num(數字)
num
是數字類型的父類,有兩個子類int
和double
。- int 整型 數值范圍在-2的53次方到2的53次方減1
- double雙精度浮點型
- int 必須是整型 double 既可以接收整型也可以接收浮點型
//print函數是控制套輸出函數
print('a 是 $a');
print('你好dart');
double c = 10;//double可以包含整型 整型 dart sdk 2.1 之前不能使用,會報錯
double d = 10.1;
print('d = $d');
num aa = -3; //num 是number類型的簡寫 abs()取絕對值
print('asdasdas' + aa.abs().toString());
//ceil() 帶小數就向前進一位取大于或者等于表達式的最小整數
num h = 8.3;
num i = h.ceil();
print(i);
//floor()舍掉小數位 不管他多大
num j = 10.9;
num k = j.floor();
//round()四舍五入
- boolean
- 布爾 關鍵字 bool 值 true 或者 false
- 布爾類型的合法值只有兩個 true 和 false 在條件判斷語句中dart不會對條件語句進行類型轉換
- 與其他語言不同 例如 JavaScript 中 布爾是非空都為true dart中只有值為true才可以 比如就算一個字符串不是空 但是他的返回值不是bool值 所以是false
bool value = true;
// bool value2 = 'asda';//不合法
bool value2 = false;
if(value){
print(value);
}
四. Dart集合
- List集合(數組)
//第一種定義List的方式
var list222 = ["asdsa","asdasd","asdsadff"];
list222.length; 獲取長度
list222[0];獲取第一個值
//第二種定義List的方式
var list111 = List();
list111.add('asdsdddda');//增加新值
list111.addAll(['hahah','asdasd']); 可以添加新的數組
//在定義List時 直接指定其類型
var List2223 = List<String>();//定義了一個只能放String類型的數組 調用其構造函數創建數組
//數組 里面的元素(值)可以重復 值的類型可以不同
List list1 = [1,2,3,4,5,6,7,8];
List list2 = [1,true,'qwe',1];
- List里面常用的屬性和方法 Map Set差不多通用
//常用屬性
length 長度
reversed 數組翻轉 對列表倒序排序
isEmpty 是否為空
isNoTEmpty 是否不為空
//常用方法
add 增加元素 增加一個
addAll 拼接數組
indexOf 查找數據 傳入具體值 查到了返回元素所在位置索引 查找不到返回-1
remove 刪除 傳入具體值
removeAt 刪除 傳入索引值
fillRange 修改數據 傳入開始索引和結束索引 然后傳入要添加的值(1,10 ,'修改的值');
insert(index,value); 指定位置插值 (1 要添加的位置在索引為1的元素前添加 ,’要添加的值‘)
insertAll(index,List); 指定位置插入List 和上面的一樣 只是傳入的是數組
toList() 其他類型轉換為List
join() List轉換為字符串 傳入變成字符串后的分割元素之間的符號
split() 字符串轉換為List 傳入通過哪些符號來分割字符串 變成List
forEach
map
where
any
every
-
Maps(字典) 也可以叫對象是無序的鍵值對
- 常用屬性:
- keys 獲取所以key值
- values 獲取所有Value值
- isEmpty 是否為空
- isNotEmpty是否不為空
- 常用方法
- remove(key) 刪除指定key的數據
- addAll({....}) 合并映射字典 給映射增加屬性
- containsValue 查看字典內是否有某個值 返回true false
- 常用屬性:
//將key和Value相關聯的對象
//key和Value都可以是任何對象
//定義方式 map字面量來定義
var person = {
"name" : "zhangsna",
"age" : 20,
"work" : ['haha','hehe']
};
//可以直接添加或者修改值
person["name"]; //取值
var per = Map();
// Map類型
Map dic = {'name': 'zhangsna', 'age': 20};
Map dic2 = new Map();//dart2.0版本后可以不用寫new關鍵字
var dic3 = new Map();
//從map中取值 如果map對象中沒有對應的鍵 返回null
print(tempMap2['sencond'].toString());
// .length 取得map對象的長度
-
Set
集合里面的值不可以重復,值的類型必須統一。最主要的功能是去除數組中重復的內容。Set是沒有順序且不能重復的集合,所以不能通過索引去獲取值。
定義有兩種形式 Set字面量 Set類型
var s = Set();
var set1 = {'value1','value2'};//Set字面量
//Set類型
//變量類型 決定
Set set2 = {};
//類型參數
var set3 = <String>{};//指定元素為String類型的Set集合
Set<String> set4 = {};
//.add()添加至到集合
set4.add('value1');
print(set4);
// .addAll 將元素為同類型的集合添加到現有集合
set4.addAll(set1);
print(set4);
// .length 得到集合的長度 里面多少個元素或者值
print(set4.length.toString());
-
常用方法
①. forEach() 傳入函數表達式 遍歷
list.forEach((value){ 遍歷數組 會把數組的每一個元素賦值給Value
print("$value");
});
②. map方法和JS里map方法很像,遍歷一個數組同時返回一個數組,遍歷同時會給出每個元素value。
var newList = lsit.map((value){
return value*2;
})
③. where方法遍歷數組得到元素同時可以加判斷語句
var newList = list.where((value){
return value>5;
})
④. any方法遍歷一個數組是否存在某個元素或者符合某些條件 返回 true false 只要集合里面有滿足條件就返回true
var newList = list.any((value){
return value>5;
})
⑤. every方法遍歷一個數組是否存在某個元素 或者 符合某些條件 每一個都滿足條件返回true否則返回false
var newList = list.every((value){
return value>5;
})
五. 運算符
- 算術運算符 + 、- 、* 、/ 、~/取整 、 %取余、 ++ 、 -- 、 += 、+-
a = b++; 會先把b賦值給a 然后在加 ++ -- 標識自增 自減 1
a = ++b; 把b加上1 在賦值給a
//在賦值運算里面如果++ -- 寫在前面 這個時候先運算 在賦值 如果++ -- 寫在后面 先賦值后運算
int aaaa = 13;
int bbbb = 5;
print(aaaa+bbbb);
print(aaaa-bbbb);
print(aaaa*bbbb);
print(aaaa/bbbb);
print(aaaa~/bbbb);
print(aaaa%bbbb);
- 關系運算符 == != > < >= <= 二元運算符
print(aaaa == bbbb);
print(aaaa != bbbb);
print(aaaa > bbbb);
print(aaaa < bbbb);
print(aaaa <= bbbb);
print(aaaa >= bbbb);
-
邏輯運算符 ! 取反 && 并且 || 與
- && 并且 條件全部為true 為true 否則false
- || 或者 或 全部為false 為false 否則 true
基礎賦值運算符 = ??= 賦值
b ??= 23; 表示如果b為空的話把23賦值給b
復合賦值運算符 += 、 -= 、 *= 、 %= 、 ~/=
三目運算符 它是唯一有3個操作數的運算符,也叫三元運算符。一般來說,三目運算符的結合性是右結合的。
var flag = true;
var ccc = flag ? '正確' : '錯誤';
- ?? 運算符
var aaa = 222;
var bbb = a ?? 333; //當a的值為空的時候把333賦值給bbb
六. 類型轉換
- Number和String類型之間的轉換
- Number類型轉換為String類型用toSting()
- String轉換為Number 用parse 通過int調用parse函數把要轉換的字符串傳進去
String ahahah = '123';
var nnnnn = int.parse(ahahah);
var nnnnn = double.parse(ahahah);//轉換為double
//如果傳入的值為空 可以通過 try catch來判斷
try{
var nnnnn = int.parse(ahahah);
}catch (err){
print('error');
//如果轉換失敗會跳到catch中
}
var aaasaa = 222;
aaasaa.isNaN //判斷是否為空
print(aaaa.toString());
七. 循環語句 流程控制語句(控制流)
- for循環
- 流程:
- 聲明變量int i = 0
- 判斷i <= 100
- print(i);
- i++
5.從第二步再來,直到判斷為false
for(int i = 0 ; i <= 100 ; i++ ){
print(i);
}
// 打印0到50所有的偶數
for(int i = 0 ; i <= 50 ; i++ ){
if(i % 2 == 0){
print(i);
}
}
//求1+2+3+4+5+++100的和
var sum = 0;
for(int i = 1 ; i <= 100 ; i++ ){
sum += i;
}
//5050;
-
while 循環 和 do while 循環
- 語法格式
- 注意點
- 最后的分號不要忘記
- 循環條件中使用的變量需要經過初始化
- 循環體中,應有結束循環的條件否則會死循環
- while語句可能一次都不執行 do while 肯定會執行一次
- 不同點 第一次循環條件不成立的情況下 while不執行循環體 do while肯定會執行一次
while(表達式/循環條件){
循環體
}
do{
語句/循環體
}while(表達式/循環條件)
if else
switch case
-
break語句
- 在switch語句中使流程跳出switch結構
- 在循環語句中使流程跳出當前循環,遇到break 循環終止,后面的代碼不會執行
break語句注意點
1.如果在循環中已經執行了break語句,就不能執行循環體中位于break后的語句。
2.在多層循環中,一個break語句只能向外跳出一層。
3.break可以用在switch case 中也可以用在for循環和while循環中。-
ontinue語句
- [注]只能在循環語句中使用,使本次循環結束,既跳過循環體重下面尚未執行的語句,接著進行下continue可以用在for循環以及while循環中,但是不建議用在while循環中,不小心容易死循環
八. Dart函數
dart中的函數 函數的定義 可選參數 默認參數 命名參數 箭頭函數 匿名函數 閉包等 函數也叫方法 在類外面叫函數 在類內部叫方法 這個都無所謂 都可以叫函數 也可以叫方法
- 自定義方法函數:
自定義方法的基本格式
返回類型 方法名稱(形式參數1,形式參數2,......){
方法體 具體執行邏輯
return 返回值;
}
print();//內置方法/函數
- 定義一個帶可選參數的方法
String method (String name ,[int age,String sex]){
//形參 可選參數放到參數后面 用[]中括號包裹 用,逗號隔開
}
- 定義一個帶默認參數的方法
String method (String name ,[String sex = '男',int age]){
//形參 如果有默認參數 建議放到 不帶默認參數的可選參數前面
}
- 定義一個命名參數的方法
String method (String name ,{String sex = '男',int age}){
//參數帶名稱的參數 需要用大括號包裹{}并且里面也可以設置默認參數
}
- 實現一個把函數當做參數的方法
fn1(){
print('fn1');
}
fn2(fn){
fn();
}
fn2(fn1);
//把方法函數fan1當做另一個方法fan2的形式參數傳進去 然后執行
- 匿名函數 沒有名字的函數
var fn = (){//沒有方法名稱
print('我是一個匿名方法');
}//直接通過變量fn調用方法
var printNumm = (){
//表示把一個函數賦值給了printNumm這個變量 調用方式和普通調用方法一樣 傳值方式和普通方法一樣
}
- 箭頭函數 箭頭函數后面只能寫一句代碼
list.forEach((valye) => print(value));
list.forEach((value) => {//里面也只能寫一句代碼
print(value)//不用寫分號
})
- 自執行方法 不主動去調用 方法自己去執行
((int n){
//方法在創建好后會自動執行 因為方法后面有括號會直接調用這個方法 可以傳入參數 和 接收參數 還可以指定類型
print('我是自執行方法');
})(12);
//就相當于在函數外面包裹了一個函數
- 方法的遞歸 一個方法可以調用自己 記得寫判斷語句 當符合條件后跳出 否則死循環
var sum = 1;
fn(int n ){
sum*=n;
if(n == 1){
return;
}
fn(n-1);//關鍵這句 在符合條件后在此執行當前方法
}
fn(10);
-
閉包:函數嵌套函數,內部函數會調用外部函數的變量或參數.
- 全局變量特點:全局變量常駐內存,全局變量污染全局
- 局部變量的特點:不會常駐內存 會被垃圾回收機制回收,不會污染全局
通過閉包可以實現:常駐內存、不污染全局,產生了閉包,閉包可以解決這個問題。
閉包寫法:函數嵌套函數,并return 里面的函數,這樣就行成了閉包
fn(){
var a = 123; /*不會污染全局 常駐內存 *//
return (){
a++;
print(a);
}
}
print(fn());
九. 類
dart所有的東西都是對象,所有的對象都繼承自Object類。是一門使用類和單繼承的面向對象語言,所有的對象都是類的實例,并且所有的類都是Object的子類。
一個類通常由屬相和方法組成
1. 定義Person類
class Person{//類名首字母大寫
String name = '張三';
int age = 23;
//dart里面的構造函數可以寫多個但是默認構造函數只能有一個
Person(String name,int age){
this.name = name;
this.age = age;
print('這是構造函數里面的內容,這個方法在實例化的時候觸發')
}
//默認構造函數簡寫
Person(this.name,this.age);
//命名構造函數 可以有多個
Person.now(){
print('我是命名構造函數');
}
void getInfo(){
print("${this.name}--$age");//this指當前類 類似self 通過this.需要用{}大括號包裹
}
}
2. 實例化類
var p1 = Person();//2.0.0后不用new關鍵字 寫也可以 推薦不寫
Person p2 = Person();//默認實例化類的時候調用的是默認構造函數
Person p3 = Person.now();//命名構造函數
var time = DateTime.now(); //實例化datetime 調用它的命名構造函數
//dart和其他面向對象語言不一樣 dart中沒有public private protected這些訪問修飾符
但是我們可以使用 “_” 下劃線 把一個屬性或者方法定義成私有
String _name;//私有屬性 私有屬性可以通過共有的方法來訪問 間接訪問私有屬性
_run(){//私有方法
print('這是一個私有方法');//也可以通過公有方法來間接調用私有方法
}
alert(){
this._run();//通過公有方法訪問私有方法 私有的不能直接訪問
}
3. 類中的getter和setter修飾符
get 名稱{ //getter方法 也就方法獲取數據
return "返回值"
}
set 名稱(形式參數){
//參數名稱 = 形式參數;
}
4. 類中的初始化列表
dart中我們也可以在構造函數體運行之前初始化實例變量
int height;
int width
Rect():height = 2 , width= 3{//在實例化之前的操作
}
5. 靜態成員
dart類中的靜態成員:
- 使用static 關鍵字來實現類級別的變量和函數
- 靜態方法不能訪問非靜態成員,非靜態方法可以訪問靜態成員
- 靜態方法成員變量不能在通過類的實例化對象訪問 直接通過類來訪問
static String name = "zhangsan";
static void show(){
}
void getInfo(){//非靜態方法可以訪問靜態成員以及非靜態成員
}
6. dart中的對象操作符
- ? 條件運算符
- as 類型轉換
- is 類型判斷
- .. 級聯操作(連綴)
p1?.方法 如果p1對象不存在會自動返回 如果存在會訪問方法
(p1 as Person).方法或者屬性 //類型轉換 轉換為自己需要的類型
Person p1 = Person();
p1..name = "hhhh";
..age = 35;//連綴操作符 訪問屬性或者方法不用對象名可以直接訪問
7. dart中的類的繼承
通過super關鍵字來繼承父類的屬性和方法
重寫父類方法是時@override關鍵字 建議加 可以不加
super.父類里面的方法 通過super調用父類的方法
- 子類使用extends類關鍵字來繼承父類
- 子類會集成父類中可見的屬性和方法 但是不會繼承構造函數
- 子類能重寫父類的方法getter和setter方法
8. dart中的抽象類 多態 和接口
dart抽象類主要用于定義標準,子類可以繼承抽象類,可以實現抽象類的接口
- 抽象類通過abstract關鍵字來定義
- dart中的抽象方法不能用abstract聲明,dart中沒有方法體的方法我們稱為抽象方法
- 如果子類繼承抽象類必須得實現里面的抽象方法
- 如果把抽象類當做接口實現的話必須得實現抽象類里面定義的所有屬性和方法
- 抽象類不能被實例化,只有繼承它的子類可以
繼承抽象類extends和implements關鍵字的區別
- 如果復用抽象類的方法,并且要用抽象方法約束自類的話我們就要用extends繼承抽象類
- 如果只是把抽象類當做標準的話我們就用implements實現抽象類、
接口:就是約定規范
首先dart的接口沒有interface關鍵字定義接口,而是普通類或者抽象類都可以作為接口被實現
同樣適用implements關鍵字進行實現
但是dart的接口有點奇怪如果實現的類是普通類 會將普通類和抽象中的屬性的方法全部需要重寫一遍
而因為抽象類可以定義抽象方法,普通類不可以,所以一般如果要實現像Java接口那樣的方式,一般會使用抽象類。
建議使用抽象類定義接口
abstract class Db{
add();//只寫方法不實現 繼承它的子類需要實現它的方法屬性
}
class Mysql implements Db{
@override
add(){
}
}
dart中一個類實現多個接口 以及dart中的Mixins混入
abstract class a{
add();//只寫方法不實現 繼承它的子類需要實現它的方法屬性
}
abstract class b{
remove();//只寫方法不實現 繼承它的子類需要實現它的方法屬性
}
class implements a,b{
//需要實現上面倆個抽象類的方法和屬性 這叫一個類實現多個接口
}
Mixins的中文意思是混入 就是類中混入其他功能,在dart中可以使用mixins實現類似多繼承的功能,因為mixins使用條件 隨著dart的版本一直在變 這里講的是dart2.x中使用mixins的條件
- 作為mixins的類只能繼承自object 不能繼承其他類
- 作為mixins的類不能有構造函數
- 一個類可以mixins多個mixins類
mixins不是繼承也不是接口 而是一種全新的特性,mixins的實例類型就是其超類的子類型 c 混入a b 就是ab的子類型。通過with關鍵字實現class c with a,b{}
c繼承了a和b class c extends Person with a,b {}
c繼承于Person類同時混入了a b 如果繼承的有同樣的方法和屬性 后面的會覆蓋前面的
9. 泛型 泛型方法 泛型類 泛型接口
通俗理解:泛型就是解決 類 接口 方法的復用性,以及對不特定數據類型的支持(類型效驗)
泛型一般在方法前面加T 啥都行 說明是泛型
①. 泛型方法
T getDate<T>(T value){
return value;
}
調用:
一般 getDate(123) 這個沒有類型校驗 傳啥返回啥。
類型校驗 getData<String>('123213'); 這個String會傳給尖括號的T代表這個方法的返回值是String 接收值也是String
②. 泛型類
class Person<T>{
List list = List<T>();
void ad(T value){
this.list.add(value);
}
}
dart中的泛型接口:
- 定義一個泛型接口 約束實現它的子類必須有getByKey(Key) 和 setBuKey(key,value)
2.要求setByKey的時候value的類型和實例化子類的時候指定的類型一致
abstract class Cache<T>{
getByKey(steing key);
void setByKey(string key ,T value);
}
class FlieCache<T> implements Cache<t>{
//繼承泛型類 把當前類定義的泛型<T>傳給父類的泛型<T>
void setByKey(string key ,T value){
}
}
③. async和await
- 只有async方法才能使用await關鍵字調用方法,如果調用別的async方法必須使用await關鍵字
- async是讓方法變成異步
- await是等待異步方法執行完成
記錄:
函數如果有一行的話可以使用箭頭函數 只要超過一行就不能使用箭頭函數 (value) => print(value);
dart中所有的類都繼承于Object類
$ 符 字符串插值運算符 $+變量名
//引入別的類
import 'package:async/async.dart';
Rune 符號文件 用來表達Unicode字符
Unicode為所有世界寫作系統中使用的每個字母、數字和符號定義了唯一的數值。
Unicode采用UTF-32位編碼 dart采用了UTF-64編碼
為了在字符串中表達32位的Unicode值需要用到特殊語法
\uXXXX 以\u開始后面跟著4個十六進制數(XXXX) , x的取值范圍是0到f
var tempStr = '\u0F00';
print(tempStr);
當到指定多于或者少于4個十六進制數字是,使用{}包裹該值
var smeil = '\u{1F600}';
print(smeil);
全局函數 可以在main方法中調用 全局作用域 方法參數被稱為形式參數 形參 調用方法傳入的參數被稱為實際參數 實參
//自定義方法
void printInfo(){
print('我是一個自定義方法');
int getNum(){//方法里面還可以嵌套方法 一個返回值為int的方法 這個方法只能在 當前函數體內調用 局部作用域
var myNum = 111;
return myNum;
}
}