Dart語言精簡入門介紹

Dart語言精簡入門介紹

1、介紹

  • Dart 在設計時應該是同時借鑒了 Java 和 JavaScript和kotlin

  • 面向對象

  • JIT&AOT:JIT(Just in Time)優點:即時編譯,開發期間更快編譯,更快的重載;缺點:在運行時將代碼編譯成機器碼,給用戶最直接的感受就是慢;AOT(Ahead Of Time)事前編譯,release期間更快更流暢,典型的例子就是C和C++,它能夠直接編譯機器碼即二進制代碼,所以它的加載和執行速度是非常快的。你會發現在開發期間安裝Flutter的時候會有一些卡頓,但是在release就是發布之后會變好,這種模式使得APP在發布之后能夠以更快的速度運行。

2、基本數據類型

  • 數字類型(num、int和double)

    1)、num:

    Dart數字類型的父類,它既接受浮點類型,也接受整數類型

    num num1 = -1.0; //num是數字類型的父類
    num num2 = 2; //num是數字類型的父類
    

    2)、int、double

    num有兩個子類,一個是int,一個是double,int類型只能接收整數,double類型是雙精度

    int int1 = 3; //子類一 int類型 只能接收整數
    double d1 = 2.22; //子類二 雙精度
    
  • 字符串(String)

    在dart中定義字符串可以用單引號也可以用雙引號,一行可以定義一個字符串,也可以定義多個字符串,中間用逗號隔開:

    String str1 = '字符串', str2 = "雙引號字符串"; //字符串的定義
    

    在dart中如何進行字符串拼接直接使用加號“+”拼接,當然還有另外一種方法,在上面數字類型的講解中也有使用到,我們可以使用"$"加上變量名去引用一個變量,這個變量可以是數字類型當然也可以是字符串類型,這個和kotlin語言有點像

    String str3 = 'str1:$str1 str2:$str2'; //字符串拼接
    String str4 = 'str1:' + str1 + "str2:" + str2; //字符串拼接
    String s = "this is dart2";
    String s2 = 'this is dart2';
    // 使用==判斷字符串是否相等
    print(s == s2); // true
    

    字符串的方法和java里面的字符串方法類似

  • 布爾

    Dart是強bool類型檢查,只有bool類型的值是true,才被認為是true

  • 集合之List

    在Dart中定義集合使用List關鍵字,List表明集合是個泛型,這里可以傳入任何數據類型。List集合可以使用“[]”進行初始化,例如:List list = [1,2,‘測試’]; 這種形式,這里沒使用泛型所以中括號里面添加元素時既可以傳入數字也可以傳入字符串,如果需要指定泛型類型,例如:List list1 = []; 這種形式下,添加元素的時候只能添加int類型的數據。

    List list = [1, 2, 3, '集合']; //初始化添加元素
    List list3 = [];
    list3.add('list3'); //通過add方法添加元素
    list3.addAll(list);
    print(list3);
    

    List集合的遍歷

    第一種:沒有語言之分的for循環方式:

    for (int i = 0; i < list.length; i++) {print(list[i]);
    }
    

    第二種:for…in…,同樣是for,但是表達式內部我們做一點修改,使用var關鍵字定義一個變量,然后使用in關鍵字在集合中進行遍歷:

    for (var o in list) {print(o);
    }
    

    第三種:forEach()循環,將函數應用于集合的每個元素,括號內傳入的為集合的元素:

    list.forEach((val) {print(val);
    });
    
  • 集合之Map

    Map集合的初始化

    Map是將key和value相關聯的對象,key和value都可以是任意類型的對象,并且key是唯一的,如果key重復,后面添加的key會替換前面的內容。

    ///Map初始化
    Map names = {'xiaoming': '小明', "xiaohong": "小紅"};
    print(names);
    Map ages = {};
    ages['xiaoming'] = 12;
    ages['xiaohong'] = 18;
    print(ages);
    

    Map的遍歷

    它的里面需要一個回調函數,回調函數里面會輸出我們的key和value

    ///Map遍歷方式
    ages.forEach((k, v) {print('$k,$v');
    });
    

    map()方法,我們可以調用Map集合的map()方法遍歷生成一個新的map集合,這個方法接收一個回調函數,入參為key、value,函數內部必須接受一個return,也就是說它會返回一個新的map,這里通過MapEntry來返回之前Map里面每一項的元素,我這里將原map的key和value進行顛倒,那么就可以得到一個相反的集合

    Map ages2 = ages.map((k, v) {return MapEntry(v, k);
    });
    print(ages2);
    

    第三種:for循環

    首先循環遍歷map集合中所有的key,可以通過map.keys獲取,它返回的是一個所有key值的數組(同樣的也有map.values),然后我們就可以通過map[key]獲取集合中的每一個元素了,代碼如下:

    for (var key in ages.keys) {print('$key , ${ages[key]}');
    }
    

3、變量聲明

  • var

    類似于 JavaScript 中的var,它可以接收任何類型的變量,但最大的不同是 Dart 中 var 變量一旦賦值,類型便會確定,則不能再改變其類型,如:

    var t = "hi world";
    // 下面代碼在dart中會報錯,因為變量t的類型已經確定為String,
    // 類型一旦確定后則不能再更改其類型。
    t = 1000;
    
  • dynamicObject

    Object 是 Dart 所有對象的根基類,也就是說在 Dart 中所有類型都是Object的子類(包括Function和Null),所以任何類型的數據都可以賦值給Object聲明的對象。 dynamicObject聲明的變量都可以賦值任意對象,且后期可以改變賦值的類型,這和 var 是不同的,如:

    dynamic t;
    Object x;
    t = "hi world";
    x = 'Hello Object';
    //下面代碼沒有問題
    t = 1000;
    x = 100
    

    dynamicObject不同的是dynamic聲明的對象編譯器會提供所有可能的組合,而Object聲明的對象只能使用 Object 的屬性與方法, 否則編譯器會報錯

     dynamic a;Object b = "";main() {a = "";printLengths();}   printLengths() {// 正常print(a.length);// 報錯 The getter 'length' is not defined for the class 'Object'print(b.length);}
    

4、常量和空安全

  • finalconst

    如果您從未打算更改一個變量,那么使用 finalconst,不是var,也不是一個類型。 一個 final 變量只能被設置一次,兩者區別在于:const 變量是一個編譯時常量(編譯時直接替換為常量值),final變量在第一次使用時被初始化。被final或者const修飾的變量,變量類型可以省略

    //可以省略String這個類型聲明
    final str = "hi world";
    //final String str = "hi world"; 
    const str1 = "hi world";
    //const String str1 = "hi world";
    
  • 空安全(null-safety)

    Dart 中一切都是對象,這意味著如果我們定義一個數字,在初始化它之前如果我們使用了它,假如沒有某種檢查機制,則不會報錯,比如:

    test() {int i; print(i*8);
    }
    

    在 Dart 引入空安全之前,上面代碼在執行前不會報錯,但會觸發一個運行時錯誤,原因是 i 的值為 null 。但現在有了空安全,則定義變量時我們可以指定變量是可空還是不可空。

    int i = 8; //默認為不可空,必須在定義時初始化。
    int? j; // 定義為可空類型,對于可空變量,我們在使用前必須判空。// 如果我們預期變量不能為空,但在定義時不能確定其初始值,則可以加上late關鍵字,
    // 表示會稍后初始化,但是在正式使用它之前必須得保證初始化過了,否則會報錯
    late int k;
    k=9;
    

    如果一個變量我們定義為可空類型,在某些情況下即使我們給它賦值過了,但是預處理器仍然有可能識別不出,這時我們就要顯式(通過在變量后面加一個”!“符號)告訴預處理器它已經不是null了,比如:

    class Test{int? i;Function? fun;say(){if(i!=null) {print(i! * 8); //因為已經判過空,所以能走到這 i 必不為null,如果沒有顯式申明,則 IDE 會報錯}if(fun!=null){fun!(); // 同上}}
    }
    

    上面中如果函數變量可空時,調用的時候可以用語法糖:

    fun?.call() // fun 不為空時則會被調用
    

    這里和kotlin有點類似

5、函數

Dart是一種真正的面向對象的語言,所以即使是函數也是對象,并且有一個類型Function。這意味著函數可以賦值給變量或作為參數傳遞給其他函數,這是函數式編程的典型特征。

  • 函數聲明

    bool isNoble(int atomicNumber) {return _nobleGases[atomicNumber] != null;
    }
    

    這里函數聲明跟java或javascript有點類似

    對于只包含一個表達式的函數,可以使用簡寫語法:

    bool isNoble (int atomicNumber)=> true ;   
    
  • 函數作為變量

    var say = (str){print(str);
    };
    say("hi world");
    
  • 函數作為參數傳遞

    void execute(var callback) {callback();
    }
    execute(() => print("xxx"))
    
  • 可選的位置參數

    String say(String from, String msg, [String device]) {var result = '$from says $msg';if (device != null) {result = '$result with a $device';}return result;
    }
    say('Bob', 'Howdy'); //結果是: Bob says Howdy
    say('Bob', 'Howdy', 'smoke signal'); //結果是:Bob says Howdy with a smoke signal
  • 可選的命名參數

    定義函數時,使用{param1, param2, …},放在參數列表的最后面,用于指定命名參數。例如:

    //設置[bold]和[hidden]標志
    void enableFlags({bool bold, bool hidden}) {// ... 
    }
    

    調用函數時,可以使用指定命名參數。例如:paramName: value

    enableFlags(bold: true, hidden: false);
    

    可選命名參數在Flutter中使用非常多。注意,不能同時使用可選的位置參數和可選的命名參數

6、類和繼承

Dart中的繼承:

1.子類使用extends關鍵詞來繼承父類

2.子類會繼承父類里面可見的屬性和方法,但是不會繼承構造函數

3.子類能復寫父類的方法 getter和setter

4.Dart 是不支持多繼承的,類和接口是統一的,類就是接口。

一般情況使用抽象類作為接口

void main() {new Student().run();
}abstract class Person {void run();
}class Student implements Person {@overridevoid run() {print("....");}
}

7、異步的支持

Dart類庫有非常多的返回Future或者Stream對象的函數。 這些函數被稱為異步函數:它們只會在設置好一些耗時操作之后返回,比如像 IO操作。而不是等到這個操作完成。

  • Future

    Future與JavaScript中的Promise非常相似,表示一個異步操作的最終完成(或失敗)及其結果值的表示。簡單來說,它就是用于處理異步操作的,異步處理成功了就執行成功的操作,異步處理失敗了就捕獲錯誤或者停止后續操作。一個Future只會對應一個結果,要么成功,要么失敗。

    由于本身功能較多,這里我們只介紹其常用的API及特性。還有,請記住,Future 的所有API的返回值仍然是一個Future對象,所以可以很方便的進行鏈式調用

    1)、Future.then

    為了方便示例,在本例中我們使用Future.delayed 創建了一個延時任務(實際場景會是一個真正的耗時任務,比如一次網絡請求),即2秒后返回結果字符串"hi world!",然后我們在then中接收異步結果并打印結果,代碼如下:

    Future.delayed(Duration(seconds: 2),(){return "hi world!";
    }).then((data){print(data);
    });
    

    2)、Future.catchError

    Future.delayed(Duration(seconds: 2),(){//return "hi world!";throw AssertionError("Error");  
    }).then((data){//執行成功會走到這里  print("success");
    }).catchError((e){//執行失敗會走到這里  print(e);
    });
    

    3)、Future.whenComplete

    有些時候,我們會遇到無論異步任務執行成功或失敗都需要做一些事的場景,比如在網絡請求前彈出加載對話框,在請求結束后關閉對話框。這種場景,有兩種方法,第一種是分別在thencatch中關閉一下對話框,第二種就是使用FuturewhenComplete回調,我們將上面示例改一下:

    Future.delayed(Duration(seconds: 2),(){//return "hi world!";throw AssertionError("Error");
    }).then((data){//執行成功會走到這里 print(data);
    }).catchError((e){//執行失敗會走到這里   print(e);
    }).whenComplete((){//無論成功或失敗都會走到這里
    });
    

    4)、Future.wait

    有些時候,我們需要等待多個異步任務都執行結束后才進行一些操作,比如我們有一個界面,需要先分別從兩個網絡接口獲取數據,獲取成功后,我們需要將兩個接口數據進行特定的處理后再顯示到UI界面上,應該怎么做?答案是Future.wait,它接受一個Future數組參數,只有數組中所有Future都執行成功后,才會觸發then的成功回調,只要有一個Future執行失敗,就會觸發錯誤回調。下面,我們通過模擬Future.delayed 來模擬兩個數據獲取的異步任務,等兩個異步任務都執行成功時,將兩個異步任務的結果拼接打印出來,代碼如下:

    Future.wait([// 2秒后返回結果  Future.delayed(Duration(seconds: 2), () {return "hello";}),// 4秒后返回結果  Future.delayed(Duration(seconds: 4), () {return " world";})
    ]).then((results){print(results[0]+results[1]);
    }).catchError((e){print(e);
    });
    

    執行上面代碼,4秒后你會在控制臺中看到“hello world”。

    5)、Async/await

    如果代碼中有大量異步邏輯,并且出現大量異步任務依賴其它異步任務的結果時,必然會出現Future.then回調中套回調情況。舉個例子,比如現在有個需求場景是用戶先登錄,登錄成功后會獲得用戶ID,然后通過用戶ID,再去請求用戶個人信息,獲取到用戶個人信息后,為了使用方便,我們需要將其緩存在本地文件系統,代碼如下:

    //先分別定義各個異步任務
    Future<String> login(String userName, String pwd){...//用戶登錄
    };
    Future<String> getUserInfo(String id){...//獲取用戶信息 
    };
    Future saveUserInfo(String userInfo){...// 保存用戶信息 
    }; 
    

    接下來,執行整個任務流:

    login("alice","******").then((id){//登錄成功后通過,id獲取用戶信息    getUserInfo(id).then((userInfo){//獲取用戶信息后保存 saveUserInfo(userInfo).then((){//保存用戶信息,接下來執行其它操作...});});
    })
    

    消除嵌套

    login("alice","******").then((id){return getUserInfo(id);
    }).then((userInfo){return saveUserInfo(userInfo);
    }).then((e){//執行接下來的操作 
    }).catchError((e){//錯誤處理  print(e);
    });
    

    使用 async/await 消除嵌套

    task() async {try{String id = await login("alice","******");String userInfo = await getUserInfo(id);await saveUserInfo(userInfo);//執行接下來的操作   } catch(e){//錯誤處理   print(e);   }  
    }
    
    • async用來表示函數是異步的,定義的函數會返回一個Future對象,可以使用 then 方法添加回調函數。

    • await 后面是一個Future,表示等待該異步任務完成,異步完成后才會往下走;await必須出現在 async 函數內部。

  • Stream

    Stream 也是用于接收異步事件數據,和 Future 不同的是,它可以接收多個異步操作的結果(成功或失敗)。 也就是說,在執行異步任務時,可以通過多次觸發成功或失敗事件來傳遞結果數據或錯誤異常。 Stream 常用于會多次讀取數據的異步任務場景,如網絡內容下載、文件讀寫等。舉個例子:

Stream.fromFutures([// 1秒后返回結果Future.delayed(Duration(seconds: 1), () {return "hello 1";}),// 拋出一個異常Future.delayed(Duration(seconds: 2),(){throw AssertionError("Error");}),// 3秒后返回結果Future.delayed(Duration(seconds: 3), () {return "hello 3";})
]).listen((data){print(data);
}, onError: (e){print(e.message);
},onDone: (){});

上面的代碼依次會輸出:

I/flutter (17666): hello 1
I/flutter (17666): Error
I/flutter (17666): hello 3

參考鏈接

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/285598.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/285598.shtml
英文地址,請注明出處:http://en.pswp.cn/news/285598.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

WPF 窗口居中 變更觸發機制

本文經原作者授權以原創方式二次分享&#xff0c;歡迎轉載、分享。原文作者&#xff1a;唐宋元明清原文地址&#xff1a;https://www.cnblogs.com/kybs0/p/7420767.html窗口居中 & 變更觸發機制解決&#xff1a;1&#xff09;單實例窗口&#xff0c;窗口每次隱藏后再顯示時…

[轉]5分鐘實現Android中更換頭像功能

5分鐘實現Android中更換頭像功能 寫在前面&#xff1a; 更換頭像這個功能在用戶界面幾乎是100%出現的。通過拍攝照片或者調用圖庫中的圖片&#xff0c;并且進行剪裁&#xff0c;來進行頭像的設置。 功能相關截圖如下&#xff1a; 下面我們直接看看完整吧&#xff1a; public cl…

Excel VBA窗體上打印系統時間print now出錯原因及解決方案

如圖所示,需要在窗體上顯示當前系統時間: 首先,我們看一下now函數的原型: Now 函數   語法:Now   說明:返回一個 Variant (Date),根據計算機系統設置的日期和時間來指定日期和時間。   示例: Private Sub CommandButton1_Click()Dim a As Varianta = NowMsgBox…

(第九周)團隊項目14

項目名&#xff1a;食物鏈教學工具 組名&#xff1a;奮斗吧兄弟 組長&#xff1a;黃興 組員&#xff1a;李俞寰、杜橋、欒驕陽、王東涵 代碼地址&#xff1a;HTTPS: https://git.coding.net/li_yuhuan/FoodChain.git SSH: gitgit.coding.net:li_yuhuan/FoodChain.git SCRUM會議…

為什么 C# 訪問 null 字段會拋異常?

一&#xff1a;背景 1. 一個有趣的話題最近在看 硬件異常 相關知識&#xff0c;發現一個有意思的空引用異常問題&#xff0c;拿出來和大家分享一下&#xff0c;為了方便講述&#xff0c;先上一段有問題的代碼。namespace ConsoleApp2 {internal class Program{static Person pe…

Android項目實戰(十五):自定義不可滑動的ListView和GridView

不可滑動的ListView (RecyclweView類似) public class NoScrollListView extends ListView {public NoScrollListView(Context context, AttributeSet attrs) {super(context,attrs);}public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ int mExpandSpec …

C語言試題一百之輸入某年某月某日,判斷這一天是這一年的第幾天

?作者簡介:大家好我是碼莎拉蒂,CSDN博客專家?????? ??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 1、題目 題目:輸入某年某月某日,判斷這一天是這一年的第幾天? 分析: 以 3 月 5 日為例,應該先把…

[轉]Java學習路線圖(完整詳細2019版)

一門永不過時的編程語言——Java 軟件開發。 Java編程語言占比&#xff1a; 據官方數據統計&#xff0c;在全球編程語言工程師的數量上&#xff0c;Java編程語言以1000萬的程序員數量位居首位。 而且很多軟件的開發都離不開Java編程&#xff0c;因此其程序員的數量最多。而在…

【CASS精品教程】Win7+CAD2008+CASS9.1(含CASS3D)完美安裝教程(附完整軟件安裝包下載)

本文講解win764位系統上安裝CAD2008+CASS9.1(含CASS3D)免費版安裝,文末附完整軟件下載地址,親測可用!!! 文章目錄 1. CAD2008安裝2. CASS9.1安裝3. 軟件下載地址1. CAD2008安裝 雙擊安裝包中的Setup.exe,開始安裝。 點擊【安裝產品】。

(十一)Jmeter另一種調試工具 HTTP Mirror Server

之前我介紹過Jmeter的一種調試工具Debug Sampler&#xff0c;它可以輸出Jmeter的變量、屬性甚至是系統屬性而不用發送真實的請求到服務器。既然這樣&#xff0c;那么HTTP Mirror Server又是做什么用的呢&#xff1f; 一、HTTP Mirror Server的作用&#xff1a; 它可以在本地臨…

C語言九十八之實現企業發放的獎金根據利潤提成。利潤(I)低于或等于 10 萬元時,獎金可提 10%;利潤高 于 10 萬元,低于 20 萬元時,低于 10 萬元的部分按 10%提成,高于 10 萬元的

?作者簡介:大家好我是碼莎拉蒂,CSDN博客專家?????? ??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 1、題目 企業發放的獎金根據利潤提成。利潤(I)低于或等于 10 萬元時,獎金可提 10%;利潤高 于 10 萬…

[轉]大數據環境搭建步驟詳解(Hadoop,Hive,Zookeeper,Kafka,Flume,Hbase,Spark等安裝與配置)

大數據環境安裝和配置&#xff08;Hadoop2.7.7&#xff0c;Hive2.3.4&#xff0c;Zookeeper3.4.10&#xff0c;Kafka2.1.0&#xff0c;Flume1.8.0&#xff0c;Hbase2.1.1&#xff0c;Spark2.4.0等&#xff09; 系統說明搭建步驟詳述 一、節點基礎配置 二、Hadoop安裝和配置三、…

C# Any()和AII()方法

我們常常需要的另一類查詢是確定數據是否滿足某個條件&#xff0c;或者確保所有數據都滿足某個條件。例如&#xff0c;需要確定某個產品是否已經脫銷(庫存為 0)&#xff0c;或者是否發生了某個交易。LINQ 提供了兩個布爾方法&#xff1a;Any()和 All()&#xff0c;它們可以快速…

樹狀數組 + 位運算 LA 4013 A Sequence of Numbers

題目傳送門 題意&#xff1a;n個數&#xff0c;兩種操作&#xff0c;一是每個數字加x&#xff0c;二是查詢& (1 << T) 1 的個數 分析&#xff1a;因為累加是永遠的&#xff0c;所以可以離線處理。樹狀數組點是c[16][M] 表示數字x%(1 << j) 后的數字pos&#x…

【地理信息系統GIS】教案(七章全)第七章:3S技術綜合應用

文章目錄 第一節 3S技術概述第二節 GIS與RS的綜合應用第三節 GIS與GPS的綜合應用第四節 網絡GIS的綜合應用第一節 3S技術概述 1.什么是“3S” 技術? 遙感(Remote Sensing ,RS); 地理信息系統(Geographical information System ,GIS); 全球定位系統(Global Positio…

初級圖像混合——線性混合操作

addWeighted函數 這個函數的作用是&#xff0c;計算兩個數組&#xff08;圖像陣列&#xff09;的加權和。原型如下&#xff1a; void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype-1); 第一個參數&am…

C語言九十九之實現一個整數,它加上 100 后是一個完全平方數,再加上 168 又是一個完全平方數,請問該數是多少?

?作者簡介:大家好我是碼莎拉蒂,CSDN博客專家?????? ??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 一、題目 一個整數,它加上 100 后是一個完全平方數,再加上 168 又是一個完全平方數,請問該數是多…

【專升本計算機】2021年甘肅省專升本計算機全真模擬試題(一)

【專升本計算機】2021年甘肅省專升本計算機全真模擬試題(一) 【專升本計算機】2021年甘肅省專升本計算機全真模擬試題(二) 【專升本計算機】2021年甘肅省專升本計算機全真模擬試題(三) 【專升本計算機】2021年甘肅省專升本計算機全真模擬試題(四) 【專升本計算機】2021…

快速掌握 ASP.NET 身份認證框架 Identity - 通過郵件重置密碼

這是 ASP.NET Core Identity 系列的第四篇文章&#xff0c;上一篇文章講解了如何在 ASP.NET Core Identity 中實現用戶登錄與登出。這篇文章講一講如何在 ASP.NET Core Identity 中通過郵件服務實現用戶賬號的密碼重置。點擊上方或后方藍字&#xff0c;閱讀 ASP.NET Core Ident…

[.net 面向對象程序設計深入](4)MVC 6 —— 談談MVC的版本變遷及新版本6.0發展方向...

[.net 面向對象程序設計深入]&#xff08;4&#xff09;MVC 6 ——談談MVC的版本變遷及新版本6.0發展方向 1.關于MVC 在本篇中不再詳細介紹MVC的基礎概念&#xff0c;這些東西百度要比我寫的全面多了&#xff0c;MVC從1.0到5.0的時間也不短了&#xff0c;很多人只是按照范例去使…