Dart函數、類和運算符-處理信息

編程語言雖然千差萬別,但歸根結底,它們的設計思想無非就是回答兩個問題:javascript

一、如何表示信息;java

二、如何處理信息;編程

函數

函數是一段用來獨立地完成某個功能的代碼。函數是對象類型,它的類型叫作Function。這意味着函數也能夠被定義爲變量,甚至能夠被定義爲參數傳遞給另外一個函數。
bool isZero(int number) => number == 0; void printInfo(int number, Function check) => print("$number is Zero: ${check(number)}"); 
若是函數體只有一行表達式,就能夠像JavaScript語言那樣用箭頭函數來簡化這個函數

一個函數中可能須要傳遞多個參數。如何讓這類函數的參數聲明變得更加優雅、可維護,同時下降調用者的使用成本?

C++與Java的作法是,提供函數的重載,即提供同名但參數不一樣的函數。但Dart認爲重載會致使混亂,所以從設計之初就不支持重載,而是提供了可選命名參數和可選參數。
bool isZero(int number) => number == 0; void printInfo(int number, Function check) => print("$number is Zero: ${check(number)}"); // 要達到可選命名參數的用法,那就在定義函數的時候給參數加上{} void enableFlagsA({bool bold, bool hidden}) => print("$bold, $hidden"); // 定義可選命名參數時增長默認值 void enableFlagesB({bool bold = true, bool hidden = false}) => print("$bold, $hidden"); // 可忽略的參數在函數定義時用[]符號指定 void enableFlagesC(bool bold, [bool hidden]) => print("$bold, $hidden"); // 定義可忽略參數時增長默認值 void enableFlagesD(bool bold, [bool hidden = false]) => print("$bold, $hidden"); 

類是特定類型的數據和方法的集合,也是建立對象的模版。

類的定義及初始化

Dart是面向對象的語言,每一個對象都是一個類的實例,都繼承自頂層類型Object。 Dart中並無public、protected、private這些關鍵字,只要在聲明變量與方法時,在前面加上_便可做爲private方法使用,若是不加_,則默認爲public。不過_的限制範圍並非類訪問級別的,而是庫訪問級別。安全

class Point { num x, y; static num factor = 0; // 語法糖,等同於在函數體內:this.x = x; this.y = y; Point(this.x, this.y); void printInfo() => print('($x,$y)'); static void printZValue() => print('$factor'); } 
有時候類的實例化須要根據參數提供多種初始化方法。除了可選命名參數和可選參數以外,Dart還提供了命名構造函數的方式,使得類的實例化過程語義更清晰。

此外,與C++相似,Dart支持初始化列表。在構造函數的函數體真正執行以前,還有機會給實例變量賦值,甚至重定向至另外一個構造函數。編程語言

class Point { num x, y, z; Point(this.x, this.y) : z = 0; // 初始化變量z Point.bottom(num x) : this(x, 0); // 重定向構造函數 void printInfo() => print('($x, $y, $z)'); } var p = Point.bottom(100); p.printInfo(); // 輸出(100,0,0) 

複用

在面向對象的編程語言中,將其餘類的變量與方法歸入本類中進行復用的方式通常有兩種:繼承父類和接口實現。ide

在Dart中,能夠對同一個父類進行繼承或接口實現:
  • 繼承父類意味着,子類由父類派生,會自動獲取父類的成員變量和方法實現,子類能夠根據須要覆寫構造函數及父類方法;
  • 接口實現則意味着,子類獲取到的僅僅是接口的成員變量符號和方法符號,須要從新實現成員變量,以及方法的聲明和初始化,不然編譯器會報錯。
class Point { num x = 0, y = 0; void printInfo() => print('($x, $y)'); } // Vector 繼承自 Point class Vector extends Point { num z = 0; @override void printInfo() => print('($x,$y,$z)'); // 覆寫了printInfo實現 } // Coordinate 是對 Point 的接口實現 class Coordinate implements Point { num x = 0, y = 0; // 成員變量須要從新聲明 void printInfo() => print('($x, $y)'); // 成員函數須要從新聲明實現 } var xxx = Vector(); xxx ..x = 1 ..y = 2 ..z = 3; // 級聯運算符,等同於 xxx.x = 1; xxx.y = 2; xxx.z = 3; xxx.printInfo(); // 輸出(1,2,3var yyy = Coordinate(); yyy ..x = 1 ..y = 2; // 級聯運算符,等同於 yyy.x = 1; yyy.y = 2; yyy.printInfo(); // 輸出 (1,2print(yyy is Point); // true print(yyy is Coordinate); // true 
除了繼承和接口實現以外,Dart還提供了另外一種機制來實現類的複用,即「混入"(Mixin),混入鼓勵代碼重用,能夠被視爲具備實現方法的接口。不只能夠解決Dart缺乏對多重繼承的支持問題,還可以避免因爲多重繼承可能致使的歧義(菱形問題)。

要使用混入,只須要with關鍵字便可。函數

class Coordinate with Point { } var yyy = Coordinate(); yyy ..x = 1 ..y = 2; // 級聯運算符,等同於 yyy.x = 1; yyy.y = 2; yyy.printInfo(); // 輸出 (1,2) print(yyy is Point); // true print(yyy is Coordinate); // true 
能夠看到,經過混入,一個類裏能夠以非繼承的方式使用其餘類中的變量與方法。

運算符

Dart和絕大多數編程語言的運算符同樣,除外,Dart多了幾個額外的運算符,用於簡化處理變量實例缺失(即null)的狀況。
  • ?. 運算符:假如Point類有printInfo()方法,p是Point的一個可能爲null的實例。那麼,p調用成員方法的安全代碼,能夠簡化爲p?.printInfo(),表示p爲nul的時候跳過,避免拋出異常。
  • ??= 運算符:若是a爲null,則給a賦值value,不然跳過。這種用默認值兜底的賦值語句在Dart中咱們能夠用a ??= value表示。
  • ?? 運算符:若是a不爲null,返回a的值,不然返回b。在Java或者C++中,咱們須要經過三元表達式(a != null)? a:b 來實現這種狀況。而在Dart中,這類代碼能夠簡化爲 a ?? b。
在Dart中,一切都是對象,就連運算符也是對象成員函數的一部分。
對於系統的運算符,通常狀況下只支持基本數據類型和標準庫中提供的類型。而對於用戶自定義的類。若是想要支持基本操做,好比比較大小、相加相減等,則須要用戶本身來定義關於這個運算符的具體實現。

Dart提供了相似C++的運算符覆寫機制,使得咱們不只能夠覆寫方法,還能夠覆寫或者自定義運算符。ui

class Vector { num x, y; Vector(this.x, this.y); // 自定義相加運算符,實現向量相加 Vector operator + (Vector v) => Vector(x + v.x, y + v.y); // 覆寫相等運算符,判斷向量相等 bool operator == (dynamic v) => x == v.x && y == v.y; } final x = Vector(3,3); final y = Vector(2,2); final z = Vector(1,1); print(x==(y+z)); // 輸出 true 
operator 是 Dart 的關鍵字,與運算符一塊兒使用,表示一個類成員運算符函數。在理解時,咱們應該把 operator 和運算符做爲總體,看做是一個成員函數名。
相關文章
相關標籤/搜索