Dart 語法學習筆記
變數
宣告變數幾種方式:
1. var name= "Tim";//自動推倒型別(infer)為string 2. String name= "Tim";//強型別定義 3. dynamic name = "Tim";//可以修改變數型別 name = 4.0; 4. final name= "Tim";//首次使用時執行一次 5. const name= "Tim";//類似全域性常量或者static,編譯期間確定值
如果沒有賦初始值,預設變數初始值為null。
內建型別
-
Numbers: 編譯期間的數字型別的常量
- int : 不大於64位,具體取決於平臺
- double : 64位
int 類實現了位移運算子;
支援0x十六進位制;
浮點型支援科學計數法
-
Strings: UTF-16 unicode 編碼
語法跟python類似
- &{express} 可以嵌入變數或者表示式
- ''' ''' 或者 """ """,可以多行顯示
- r'', raw字串
- In Dart, runes are the UTF-32 code points of a string.
-
Booleans: 同樣是編譯期間常量。
- bool 識別符號,true & false
- if (nonbooleanValue) 這樣比較是不行的,必須顯示的比較或者呼叫類isEmpty方法。
-
Lists: 陣列
- 如果想要宣告一個編譯期常量的陣列:var constantList = const [1, 2, 3]; //必須指定為const
-
Maps: 字典 同js
-
Runes: UTF-32 字串。比如一些符號,表情等。\uXXXX
-
Symbols: 不會用到。針對API推斷識別符號有用。
函式
Dart是一個真正的面向物件程式語言,一切都是物件,函式也是一個物件,它的型別是Function。
跟c語言函式語法一樣,但是可以省略返回值型別和引數型別。
也有自己的速寫語法:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null; 等價於 bool isNoble(int atomicNumber) { return _nobleGases[atomicNumber] != null; }
=> expr 是{ return expr; } 的簡寫。expr只能是一個語句,否則必須用{}方式。
一、引數
1. 函式呼叫時,可以使用 name:value方式制定引數。順序可以不是宣告順序。 2. @require 關鍵字,標示該引數必須傳入。 3. 可選引數,使用[]擴起來。必須放到引數的最後位置,且不能存在多個[]的可選位置引數。 4. 引數可以設定預設值,如果沒有設定預設值,預設為null。
二、.. 操作符,可以看作是鏈式程式設計的語法。object.func1()..func2()..func3();
三、函式可以作為引數傳遞給函式,作用同對象引數一樣。
四、匿名函式、lambda表示式、閉包。是一個概念。
五、返回值:所有函式都有一個返回值,預設返回return null;
運算子
很多操作跟c運算子一致,這裡不做過多介紹。下面只介紹特殊運算子:
~/: 除法,返回整數 as: 型別判斷 is、is!: 型別檢測 ..: 嚴格來說,double dot不是操作符,而是Dart的語法。對同一個物件做一系列操作,類似鏈式程式設計。 ??=: 賦值,只有當左值為null的時候,才賦值。 // 只有當b是null的時候,給b賦值value; 否則b保持原值不變 b ??=: value; ??: 條件運算子,簡化if..else語句。expr1 ?? expr2,如果expr1不為null, 返回expr1; 否則返回expr2。 ?.: 類似.操作符,獲取成員。問號的作用是標示物件可以是null
控制流
- if..else: 條件必須是boolean型別
-
for:
- 傳統for語法
- for-in:可迭代的類或者型別才支援。例如:List, Set等
- While and do-while
- Break and continue
- Switch and case: int和string都可以作為case條件;每個case後必須有break語句;不支援空case;
var command = 'CLOSED'; switch (command) { case 'CLOSED': executeClosed(); continue nowClosed; // Continues executing at the nowClosed label. nowClosed: case 'NOW_CLOSED': // Runs for both CLOSED and NOW_CLOSED. executeNowClosed(); break; }
- Assert
異常處理
- Throw: 可以丟擲非null的任何物件,包括exception和error物件。
-
Catch: 語法如下:
on
可以捕獲具體型別的exception;catch 可以跟on一起,也可以單獨使用。最多包含兩個引數,e
是丟擲的異常,s
是堆疊資訊。
try { breedMoreLlamas(); } on OutOfLlamasException { // A specific exception buyMoreLlamas(); } on Exception catch (e) { // Anything else that is an exception print('Unknown exception: $e'); } catch (e) { // No specified type, handles all print('Something really unknown: $e'); } try { // ··· } on Exception catch (e) { print('Exception details:\n $e'); } catch (e, s) { print('Exception details:\n $e'); print('Stack trace:\n $s'); }
- rethrow: 再次丟擲異常
void misbehave() { try { dynamic foo = true; print(foo++); // Runtime error } catch (e) { print('misbehave() partially handled ${e.runtimeType}.'); rethrow; // Allow callers to see the exception. } } void main() { try { misbehave(); } catch (e) { print('main() finished handling ${e.runtimeType}.'); } }
- Finally: 捕獲異常後後會繼續執行finally中的內容。
try { breedMoreLlamas(); } catch (e) { print('Error: $e'); // Handle the exception first. } finally { cleanLlamaStalls(); // Then clean up. }
類
- 使用類成員: 使用.運算子引用物件成員和方法。
// If p is non-null, set its y value to 4. p?.y = 4;
- 使用建構函式: Dart 2中new操作符可選。建構函式可以是類名,也可以是類名.識別符號。
var p1 = Point(2, 2); var p2 = Point.fromJson({'x': 1, 'y': 2});
-
獲取物件型別:使用runtimeType屬性。(Object物件定義,獲取執行時物件型別)
-
成員變數
沒有public、private、protected關鍵字。
不需要設定成員變數預設值,不初始化的變數預設null。
預設會對成員變數生成隱式的get和set方法。
-
建構函式
建構函式可以是跟類名一樣的名字,也可以宣告其他名字。
class Point { num x, y; Point(num x, num y) { // Use this only when there is a name conflict this.x = x; this.y = y; } // Syntactic sugar for setting x and y // before the constructor body runs. // Point(this.x, this.y); 等同於上面的建構函式,寫法更簡單 // Named constructor:使用:Point p = Point.origin(); Point.origin() { x = 0; y = 0; } }
如果不寫建構函式,會預設生成一個建構函式;預設生成的建構函式跟類同名,沒有引數。
建構函式不能繼承。預設子類會呼叫基類的預設建構函式或者無引數建構函式。
跟C++一樣,Dart也有初始化列表(initializer list)。初始化列表要寫在呼叫基類建構函式之前。
// Initializer list sets instance variables before // the constructor body runs. Point.fromJson(Map<String, num> json) : x = json['x'], y = json['y'] { print('In Point.fromJson(): ($x, $y)'); }
重定向建構函式:重定向建構函式的函式體必須為空,通過冒號在後面定向到其他建構函式.
class Point { num x, y; // The main constructor for this class. Point(this.x, this.y); // Delegates to the main constructor. Point.alongXAxis(num x) : this(x, 0); }
常量建構函式:可以建立一個編譯時的常量物件,物件建構函式引數必須時常量。用於建立一個不變的物件(內部成員不會改變)
class ImmutablePoint { static final ImmutablePoint origin = const ImmutablePoint(0, 0); final num x, y; const ImmutablePoint(this.x, this.y); }
工廠建構函式:不能直接使用this。可以從cache獲取例項,也可能建立子型別的物件。
class Logger { final String name; bool mute = false; // _cache is library-private, thanks to // the _ in front of its name. static final Map<String, Logger> _cache = <String, Logger>{}; //工廠建構函式 factory Logger(String name) { if (_cache.containsKey(name)) { return _cache[name]; } else { final logger = Logger._internal(name); _cache[name] = logger; return logger; } } Logger._internal(this.name); void log(String msg) { if (!mute) print(msg); } }
-
成員函式
getter和setter方法,是預設生成用於存取成員變數的成員函式。也可以顯式宣告(使用get和set關鍵字)
class Rectangle { num left, top, width, height; Rectangle(this.left, this.top, this.width, this.height); // Define two calculated properties: right and bottom. num get right => left + width; set right(num value) => left = value - width; num get bottom => top + height; set bottom(num value) => top = value - height; }
抽象方法:類似C++中的虛基類中的虛擬函式,基類中沒有實現,子類實現。
-
抽象類:
跟C++不同的是,可以通過工廠建構函式(factory constructor)建立例項。
-
隱含介面(Implicit interfaces):使用implements關鍵字,可以實現類的方法,可以實現多重繼承。
// A person. The implicit interface contains greet(). class Person { // In the interface, but visible only in this library. final _name; // Not in the interface, since this is a constructor. Person(this._name); // In the interface. String greet(String who) => 'Hello, $who. I am $_name.'; } // An implementation of the Person interface. class Impostor implements Person { get _name => ''; String greet(String who) => 'Hi $who. Do you know who I am?'; } String greetBob(Person person) => person.greet('Bob'); void main() { print(greetBob(Person('Kathy'))); print(greetBob(Impostor())); } class Point implements Comparable, Location {...}
-
擴充套件一個類
關鍵字extends建立子類,使用super指向其基類。
@override 關鍵字用來覆蓋基類的實現。
covariant 關鍵字:表示收緊子型別
class Animal { void chase(Animal x) { ... } } class Mouse extends Animal { ... } class Cat extends Animal { //只能傳Mouse和其子類 void chase(covariant Mouse x) { ... } }
不能訪問一個不存在的成員函式,但是可以通過覆蓋noSuchMethod()方法,使程式碼不丟擲異常。
-
列舉型別:可以表示固定的常數的一種特殊的類。預設值index從0開始。
enum Color { red, green, blue } //使用enum關鍵字定義列舉 assert(Color.red.index == 0); assert(Color.green.index == 1); assert(Color.blue.index == 2);
列舉型別使用的限制:
- 不能繼承,混合和實現一個列舉。
- 不能顯式的實現一個列舉類。
-
向類中新增特性:使用mixins技術(類似多重繼承)
關鍵字
with
class T = A with S;
那我們得到的class T是怎麼樣的呢?假設MA表示A中的所有方法,MS表示S中的所有方法,那麼T中的方法集合為:MS U (MA - MS)
。複雜一點的情況:
class T = B with A, S;
==class T = (B with A) with S;
-
類成員和方法:同樣使用
static
關鍵字。
泛型
可以在執行時判斷泛型型別內容的具體type。其他方面跟java或者c++差不多。
庫和可見性
- 使用import匯入要使用的庫。
- 如果匯入的多個庫中,有同名類或者函式,可以通過別名區分。關鍵字as。類似c++中的namespace。
import 'package:lib1/lib1.dart'; import 'package:lib2/lib2.dart' as lib2; // Uses Element from lib1. Element element1 = Element(); // Uses Element from lib2. lib2.Element element2 = lib2.Element();
-
也可以僅僅匯入庫中的部分內容
show
和hide
關鍵字
// Import only foo. import 'package:lib1/lib1.dart' show foo; // Import all names EXCEPT foo. import 'package:lib2/lib2.dart' hide foo;
-
懶載入庫
deferred as
關鍵字
import 'package:greetings/hello.dart' deferred as hello; Future greet() async { await hello.loadLibrary(); hello.printGreeting(); }
- 如何實現庫。單獨章節進行講解。
非同步支援
關鍵字async
和await
支援非同步程式設計。
生成器
參考python中的生成器。
需要後續加強了解
可呼叫的類
Dart 語言中為了能夠讓類像函式一樣能夠被呼叫,可以實現call()方法。
具體使用的場景,需要調研
隔離
沙盒?
Typedefs
Dart中,函式也是物件。Function關鍵字,typedefs 可以給函式設定別名。
元資料
A metadata annotation begins with the character @, followed by either a reference to a compile-time constant (such as deprecated) or a call to a constant constructor.
Two annotations are available to all Dart code: @deprecated and @override.
註釋
-
單行
//
-
多行
/* */
-
文件註釋
///
或者/**