-
用
var
聲明變量,如果初始化時不指定類型(即只聲明不賦值)蹬屹,則其是動態(tài)類型dynamic
柏蘑,可以給其賦值任意類型的值狂窑。如果指定了類型,則其類型就確定了染厅,后續(xù)不能更改痘绎。var a; // 初始化沒有指定類型,a 為動態(tài)類型(相當于:dynamic a;) a = 2; // ? a = 'hello'; // ? var b = 1; // 初始化就確定了值的類型肖粮,b的類型不能再更改(相當于:int b = 1;) b = 'hello'; // ?
-
final
修飾的變量在聲明時必須初始化孤页,且不能被再次賦值。void main() { int a; // ? final a = 1; ? final a; // ? }
-
const
聲明的必須是編譯器常量
涩馆。int getNum() { return 1; } void main() { final a = getNum(); // ? const b = getNum(); // ? }
-
int
和double
都是num
類型的子類int a = 1; a = 1.1; // ? (不能把 double 類型賦值給 int 類型) num c = 3; // 用 num 類型聲明 c行施,c 既可以是 int 類型允坚,也可以是 double 類型 c = 3.3 // ?
-
通過提供一個
r
前綴,可以創(chuàng)建一個原始raw
字符串var s = r"In a raw string, even \n isn't special."; print(s); // 不會產(chǎn)生換行效果蛾号,打印結(jié)果為:In a raw string, even \n isn't special.
-
如果一個對象等于
null
稠项,調(diào)用它的方法,運行時會報錯List a; a.add(1); // ? Unhandled Exception: NoSuchMethodError: The method 'add' was called on null. a?.add(1); // ? 由于 ? 判斷出 a 等于 null鲜结,便直接忽略掉后續(xù)操作:add()
-
用
const
定義一個不可變的List
展运,如果執(zhí)行修改操作,運行時會報錯List a = const [1, 2]; a.add(3); // ? Unhandled Exception: Unsupported operation: Cannot add to an unmodifiable list
-
as
精刷、is
拗胜、is!
操作符在運行時用于檢查類型非常方便as:類型轉(zhuǎn)換 is:當對象是相應(yīng)類型時返回 true is!:當對象不是相應(yīng)類型時返回 true
-
賦值操作符
??=
,僅當變量為null
時賦值var a = 1; a ??= 2; // print(a) // 輸出 1 var b; b ??= 2; print(b) // 輸出 2
級聯(lián)符號
..
querySelector('#confirm') // 獲取一個對象
..text = 'Confirm' // 使用它的成員
..classes.add('important')
..onClick.listen((e) => window.alert('confirmed!'));
上述代碼相當于:
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('confirmed'));
可以看出贬养,遵循級聯(lián)符號的代碼都是對第一個方法返回的 button
對象進行操作挤土,而忽略任何可能返回的后續(xù)值。
級聯(lián)操作符可以嵌套:
final addressBook = (AddressBookBuilder()
..name = 'jenny'
..email = 'jenny@example.com'
..phone = (PhoneNumberBuilder()
..number = '415-555-0100'
..label = 'home')
.build())
.build();
注意:
var a = StringBuffer();
a.write('foo') // 這兒是用的'.'误算,而非級聯(lián)運算符'..'
..write('bar'); // ? 第一個 a.write() 返回值是 void,返回值為 void 的方法則不能使用級聯(lián)運算符
var b = StringBuffer();
b
..write('foo')
..write('bar'); // ?
-
使用
dynamic
方式定義方法getUser(name) => '$name is very good!'; // 參數(shù)和返回值類型都是 dynamic 的 print(getUser('zhangsan'));
-
方法的參數(shù):
-
必要參數(shù)迷殿;
getProduct(num id, String description) {}; getProduct(1, 'description'); // ? getProduct(id: 1, description: 'description'); // ? 調(diào)用時 不能寫參數(shù)名
-
可選參數(shù):
-
命名參數(shù)儿礼,表達形式:{k: v} 鍵值對;
getProduct({bool flag, String name}) {}; getProduct(); // ? getProduct(flag: true); // ? getProduct(name: 'zhangsan'); // ? getProduct(flag: true, name: 'zhangsan'); // ?
-
位置參數(shù)庆寺,表達形式:[type name]
getProduct([bool flag, String name]) {}; getProduct(true); // ? getProduct(true, 'zhangsan'); // ? getProduct(null, 'zhangsan'); // ? getProduct('zhangsan'); // ? 必須傳前面的 flag 參數(shù)蚊夫,否則會提示 String和bool 類型不匹配 getProduct(flag: true, name: 'zhangsan'); // ? 調(diào)用時 不能寫參數(shù)名
-
注意:不能同時使用可選的位置參數(shù)和可選的命名參數(shù)。必要參數(shù)定義在參數(shù)列表前面懦尝,可選參數(shù)則定義在必要參數(shù)后面知纷。
-
-
Dart 中的構(gòu)造方法是不支持重載的,可以通過 命名的構(gòu)造方法 來實現(xiàn)構(gòu)造方法的重載:
class Student { String name; final int gender; Student(this.name, this.gender); // 命名的構(gòu)造方法 Student.withName(this.gender) {} }
注意:用
final
修飾的屬性gender
陵霉,不能用如下寫法來初始化:Student(String name, int gender) { this.name = name; this.gender = gender; // ? 'gender' can't be used as a setter because it is final. }
-
常量構(gòu)造方法琅轧,需要把該類的構(gòu)造方法用
const
修飾,并且該類的所有實例屬性必須是final
的class Student { final String name; final int age; // 常量構(gòu)造方法 const const Student(this.name, this.age); } const s = Student('zhangsan', 18);
-
getter
方法class Student { int _age; int get age => _age; // 或 int get age { return _age; } }
-
setter
方法class Student { int _age; set age(int age) => _age = age; // 或 set age(int age) { _age = age; } }
-
factory
工廠構(gòu)造函數(shù):使用factory
關(guān)鍵字標識的構(gòu)造函數(shù)踊挠,意味著使用該構(gòu)造函數(shù) 構(gòu)造類的實例時乍桂,并非總是會返回新的實例對象。例如效床,工廠構(gòu)造函數(shù)可能會從緩存中返回一個實例睹酌,或者返回一個子類型的實例。class Person { static final Map<String, Person> _cache = {}; // 工廠構(gòu)造方法 factory Person() { return _cache.putIfAbsent('p', () => Person._inner()); } // 命名的私有構(gòu)造方法 Person._inner(); } var a = Person(); // 緩存中沒有剩檀,a 是新建的實例憋沿,并存入 緩存 _cache 中 var b = Person(); // 緩存中有了,b 是從緩存 _cache 中讀取的實例 print(a == b); // 輸出 true
-
如果類實現(xiàn)了
call
方法沪猴,則該類的對象可以作為方法使用class Student { call(int x, int y) { // 可以不加參數(shù) print(x + y); } } var a = Student(); a(1, 2); // 輸出 3
-
abstract
抽象類中的抽象方法辐啄,子類必須重寫abstract class Person { say() {} // 普通方法或?qū)傩? sleep(); // 抽象方法 } class Student extends Person { @override sleep() { // TODO: implement sleep return null; } }
抽象類常用于聲明接口方法采章,通常不能被實例化,但有時也會有具體的方法實現(xiàn)则披。如果想讓抽象類同時可被實例化共缕,可以為其定義 工廠構(gòu)造函數(shù)。
-
Dart 是單繼承士复,但一個類可以 實現(xiàn)
implements
多個接口图谷。class Point implements Comparable, Location {...}
-
import
時使用as
可以為模塊中的代碼重命名(可以避免不同模塊中的同名代碼沖突),白可以使用show
或hide
關(guān)鍵字來 指定 暴露或隱藏 模塊中的部分代碼阱洪。import './one.dart' as lib1; import './two.dart' as lib2 show method2; // lib2 中僅 method2 方法可見 import './three.dart' as lib3 hide method3, mehtod33; // lib3 中的 method3 和 method33 方法不可見
在
Container
中嵌套Container
便贵,如果不設(shè)置 外層Container
的alignment
,則內(nèi)層的Container
會填滿外層的Container
冗荸,內(nèi)層Container
設(shè)置的寬高會被忽略承璃。