Flutter日漸火爆,因此在進(jìn)行Flutter學(xué)習(xí)前先學(xué)習(xí)一些其所使用的開發(fā)語(yǔ)言dart的基礎(chǔ),這篇文章主要學(xué)習(xí)了
- Dart的基礎(chǔ)代碼示例
- Dart的概念
- Dart的關(guān)鍵字
Dart的基礎(chǔ)代碼示例
// 定義一個(gè)方法。
printInteger(int aNumber) {
print('The number is $aNumber.'); // Print to console.
}
// main入口函數(shù)。
main() {
var number = 42; // 聲明并初始化變量。
printInteger(number); // 函數(shù)調(diào)用。
}
// 注釋
dart注釋方法,更多注釋可以看我的另一篇文章http://www.itdecent.cn/p/d1dae0d5c472
int
數(shù)據(jù)類型,更多數(shù)據(jù)類型可看https://www.dartlang.org/guides/language/language-tour#built-in-types
print()
一種方便的顯示輸出方式
'...' (or "...")
字符串,dart中更推薦使用'...'
$variableName (or ${expression})
字符串插值:包括字符串文字內(nèi)部的變量或表達(dá)式的字符串
var
一種聲明變量而不指定其類型的方法,關(guān)鍵字之一
Dart重要概念
當(dāng)要學(xué)習(xí)dart時(shí),請(qǐng)記住以下事實(shí)和概念:
-
一切皆為對(duì)象,放在變量中的所有內(nèi)容都是一個(gè)對(duì)象,每個(gè)對(duì)象都是一個(gè)class的實(shí)例,numbers,函數(shù)和null都是對(duì)象,所有對(duì)象都繼承自O(shè)bject類。下面給個(gè)圖你看一下,沒(méi)錯(cuò),連int都是對(duì)象:
int 盡管Dart是強(qiáng)類型的,但類型注釋是可選的,因?yàn)镈art可以推斷類型。在上面的代碼中,數(shù)字被推斷為int類型。如果要明確說(shuō)明不需要任何類型,請(qǐng)使用特殊類型dynamic。
Dart支持泛型類型,如List<int>(整數(shù)列表)或List<dynamic>(任何類型的對(duì)象列表)。
Dart支持頂級(jí)函數(shù)(例如main()),以及綁定到類或?qū)ο蟮暮瘮?shù)(分別是靜態(tài)和實(shí)例方法),還可以在函數(shù)內(nèi)創(chuàng)建函數(shù)(嵌套函數(shù)或本地函數(shù))。
Dart也支持頂級(jí)變量,以及綁定到類或?qū)ο蟮淖兞?靜態(tài)和實(shí)例變量),實(shí)例變量有時(shí)稱為字段或?qū)傩浴?/p>
與Java不同,Dart沒(méi)有關(guān)鍵字public,protected和private,如果標(biāo)識(shí)符以下劃線(_)開頭,則它代表是私有的,否則都為公有。
標(biāo)識(shí)符可以以字母或下劃線(_)開頭,后跟這些字符加數(shù)字的任意組合。
Dart有表達(dá)式(具有運(yùn)行時(shí)值)和語(yǔ)句(不具有運(yùn)行時(shí)值)。例如,條件表達(dá)式"條件? expr1:expr2的值為expr1或expr2"。將其與if-else語(yǔ)句進(jìn)行比較,該語(yǔ)句沒(méi)有任何值。語(yǔ)句通常包含一個(gè)或多個(gè)表達(dá)式,但表達(dá)式不能直接包含語(yǔ)句。
關(guān)鍵字
dart共有60個(gè)關(guān)鍵字,所以以下篇幅可能有點(diǎn)長(zhǎng)
| abstract2 | dynamic2 | implements2 | show1 |
| as2 | else | import2 | static2 |
| assert | enum | in | super |
| async1 | export2 | in2 | super |
| await3 | extends | is | sync1 |
| break | external2 | library2 | this |
| case | factory2 | mixin2 | throw |
| catch | false | new | true |
| class | final | null | try |
| const | finally | on1 | typedef2 |
| continue | for | operator2 | var |
| covariant2 | Function2 | part2 | void |
| default | get2 | rethrow | while |
| deferred2 | hide1 | return | with |
| do | if | set2 | yield3 |
- 帶有上標(biāo)1的關(guān)鍵字是上下文關(guān)鍵字,僅在特定位置具有含義。
- 帶有上標(biāo)2的關(guān)鍵字是內(nèi)置標(biāo)識(shí)符, 為了簡(jiǎn)化將JavaScript代碼移植到Dart的任務(wù),這些關(guān)鍵字在大多數(shù)地方都是有效的標(biāo)識(shí)符,但它們不能用作類或類型名稱,也不能用作導(dǎo)入前綴。
- 帶有上標(biāo)3的關(guān)鍵字為新版本中的新標(biāo)識(shí)符,是與Dart 1.0發(fā)布后添加的異步支持相關(guān)的有限保留字。
詳細(xì)可看下面說(shuō)明
abstract
使用abstract修飾符定義抽象類即無(wú)法實(shí)例化的類,抽象類可以自定義一些接口。抽象類通常有抽象方法,下面是一個(gè)聲明具有抽象方法的抽象類的示例:
// 該類聲明為抽象類且不可實(shí)例化。
abstract class AbstractContainer {
// 定義構(gòu)造函數(shù),變量,方法等...
// 其他....
// 抽象方法。
void updateChildren();
}
下面為實(shí)現(xiàn)抽象方法的例子:
//抽象類
abstract class Doer {
void doSomething(); // 定義一個(gè)抽象方法
}
//繼承抽象類實(shí)現(xiàn)抽象方法
class EffectiveDoer extends Doer {
void doSomething() {
// 實(shí)現(xiàn)邏輯
}
}
dynamic
顧名思義,dynamic(動(dòng)態(tài)), 直接先上代碼
void judge(dynamic arg){
if (arg is bool){
print('arg is bool');
} else if (arg is String){
print('arg is String');
} else if (arg is int){
print('arg is int');
} else {
print('arg is others');
}
}
dynamic同等于Object, 即上面代碼可以等同于下面代碼:
void judge(Object arg){
if (arg is bool){
print('arg is bool');
} else if (arg is String){
print('arg is String');
} else if (arg is int){
print('arg is int');
} else {
print('arg is others');
}
}
在Dart中,dynamic和Object可表示所有類型, 這兩者區(qū)別是使用dynamic可以處理更復(fù)雜的不確定類型,例如超出了Dart的類型系統(tǒng),或者值來(lái)自互操作或者在靜態(tài)類型系統(tǒng)范圍之外的情況。
implements
Java中,該關(guān)鍵字用于實(shí)現(xiàn)接口類(interface), Dart中亦有相同的意思,實(shí)現(xiàn)接口,我們先看代碼:
// Person類,包含方法greet().
class Person {
//在該類中,屬于私有,僅對(duì)當(dāng)前類可見
final _name;
// 不是接口,只是構(gòu)造函數(shù)
Person(this._name);
// 接口
String greet(String who) => 'Hello, $who. I am $_name.';
}
// 實(shí)現(xiàn)Person類接口的類
class Impostor implements Person {
//只是一個(gè)普通的get方法,可忽略
get _name => '';
//實(shí)現(xiàn)Person的greet方法
String greet(String who) => 'Hi $who. Do you know who I am?';
}
//只是一個(gè)測(cè)試方法
String greetBob(Person person) => person.greet('Bob');
void main() {
print(greetBob(Person('Kathy'))); //打印 -> Hello, Bob. I am Kathy.
print(greetBob(Impostor())); //打印 -> Hi Bob. Do you know who I am?
}
Dart中沒(méi)有Java的interface功能,如果Impostor在不繼承Person類的情況想實(shí)現(xiàn)Person類的接口的話,可以使用implements關(guān)鍵字。implements可同時(shí)實(shí)現(xiàn)多個(gè)類的接口:
class Point implements Comparable, Location {...}
show & hide
有時(shí)候我們導(dǎo)入一個(gè)庫(kù),如果只想使用庫(kù)的一部分,則可以有選擇地導(dǎo)入庫(kù),例如:
// 只導(dǎo)入foo
import 'package:lib1/lib1.dart' show foo;
//導(dǎo)入整個(gè)庫(kù)除了foo
import 'package:lib2/lib2.dart' hide foo;
as, is, is!
as,is,和 !is 運(yùn)算符在運(yùn)行時(shí)檢查類型很方便
- as: 類型轉(zhuǎn)換, 也用于指定庫(kù)前綴
- is: 類似于java的instanceof
- !is: is操作符的取反, 即不是xxx
代碼示例:
if (emp is Person) {
// 類型檢查
emp.firstName = 'Bob';
}
// 如果emp為Person,則將firstName改為Bod, 否則會(huì)在運(yùn)行時(shí)期報(bào)錯(cuò)
(emp as Person).firstName = 'Bob';
如果導(dǎo)入兩個(gè)具有沖突標(biāo)識(shí)符(class)的庫(kù),則可以為一個(gè)或兩個(gè)庫(kù)指定前綴。 例如,如果library1和library2都有一個(gè)Element類,那么as可以這樣使用:
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2; //指定庫(kù)的前綴為lib2
// Uses Element from lib1.
Element element1 = Element();
// Uses Element from lib2.
lib2.Element element2 = lib2.Element();
if & else
與Java或其他語(yǔ)言一樣,Dart支持帶有可選else語(yǔ)句的if語(yǔ)句:
if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}
import
與Java一樣,使用import導(dǎo)入其他包。例如,Dart Web應(yīng)用程序通常使用dart:html庫(kù),可以這樣導(dǎo)入:
import 'dart:html';
如果只是想導(dǎo)入某個(gè)包下的某個(gè)dart文件,可以這樣導(dǎo)入:
import 'package:test/test.dart'; //指定導(dǎo)入test.dart(類似于Java中的test.java)
static
使用static關(guān)鍵字實(shí)現(xiàn)類范圍的變量和方法
static變量(只有在使用的時(shí)候才會(huì)進(jìn)行初始化):
class Queue {
static const initialCapacity = 16;
// ···
}
void main() {
assert(Queue.initialCapacity == 16);
}
static方法:
import 'dart:math';
class Point {
num x, y;
Point(this.x, this.y);
static num distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}
void main() {
var a = Point(2, 2);
var b = Point(4, 4);
var distance = Point.distanceBetween(a, b); //靜態(tài)方法,不用實(shí)例化
assert(2.8 < distance && distance < 2.9);
print(distance);
}
assert
斷言assert(條件);
如果條件為返回false,使用assert語(yǔ)句可以中斷正常執(zhí)行, 代碼:
// text等于null時(shí)中斷
assert(text != null);
// number > 100時(shí)中斷
assert(number < 100);
// 如果urlString不是以"https"開頭
assert(urlString.startsWith('https'));
如果要附加一個(gè)消息到斷言,可在第二個(gè)參數(shù)輸入一個(gè)字符串:
assert(urlString.startsWith('https'),
'URL ($urlString) should start with "https".');
enum
枚舉類型(通常稱為枚舉或枚舉)是一種特殊類型,用于表示固定數(shù)量的常量值。
使用enum關(guān)鍵字聲明枚舉類型, 例如:
enum Color { red, green, blue }
枚舉中的每個(gè)值都有一個(gè)索引getter,它返回枚舉聲明中值的從零開始的位置。 例如,第一個(gè)值具有索引0,第二個(gè)值具有索引1:
print('red index: \${Color.red.index}'); // -> 打印red index: 0
print('green index: \${Color.green.index}'); // -> 打印: green index: 1
print('blue index: \${Color.blue.index}');· //-> 打印: blue index: 2
要獲取枚舉中所有值的列表,可以使用以下方法:
List<Color> colors = Color.values;
您可以在switch語(yǔ)句中使用枚舉,如果您不處理所有枚舉值,您將收到警告:
var aColor = Color.blue;
switch (aColor) {
case Color.red:
print('Red as roses!');
break;
case Color.green:
print('Green as grass!');
break;
default: // 沒(méi)有這行代碼的話,會(huì)有一個(gè)警告
print(aColor); // 'Color.blue'
}
枚舉類型具有以下限制:
1.不能子類化,混合或?qū)崿F(xiàn)枚舉。
2.無(wú)法顯式實(shí)例化枚舉。
for & in
可以使用標(biāo)準(zhǔn)for循環(huán)進(jìn)行迭代, 例如:
var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
message.write('!');
}
像List和Set這樣的可迭代類支持使用的for-in形式迭代:
var list = [0, 1, 2];
for (var x in list) {
print(x); // 0 1 2
}
等同于:
for (int i = 0; i < list.length; i++){
print(list[i]); // 0 1 2
}
extend & super
使用extends來(lái)繼承一個(gè)類,使用super來(lái)調(diào)用父類:
class Television {
void turnOn() {
_illuminateDisplay();
_activateIrSensor();
}
// ···
}
class SmartTelevision extends Television {
void turnOn() {
super.turnOn(); //調(diào)用父類方法
_bootNetworkInterface();
_initializeMemory();
_upgradeApps();
}
// ···
}
async & await
- async -> 異步
- await -> 等待
Dart庫(kù)中包含許多返回Future或Stream對(duì)象的函數(shù),關(guān)于Future和Steam會(huì)在后續(xù)進(jìn)行講解,這里暫不深究。 這些函數(shù)是異步的:它們?cè)谠O(shè)置可能耗時(shí)的操作(例如I/O)后返回,而不等待該操作完成。
async和await關(guān)鍵字用于異步編程
async關(guān)鍵字修飾一個(gè)方法,要求必須返回一個(gè)Future對(duì)象,下面為代碼例子:
//async關(guān)鍵字聲明該函數(shù)內(nèi)部有代碼需要延遲執(zhí)行
Future<String> getResult() async {
return await getResultFromDb(); //await關(guān)鍵字聲明運(yùn)算為延遲執(zhí)行,然后返回運(yùn)算結(jié)果
}
Future<String> getResultFromDb() {
// 很多延時(shí)操作
// 很多延時(shí)操作
// 很多延時(shí)操作
// 很多延時(shí)操作
return new Future((){
return 'This is server...';
});
}
//打?。簉esult = This is server...
print(getResult().then((result){
print('result = $result');
}));
export
我們來(lái)看一個(gè)官方的http庫(kù)的代碼: http: ^0.12.0

我們可以看到該包下面有一個(gè)src目錄,還有一些其他的dart文件,Dart庫(kù)中,lib/src下的代碼被認(rèn)為是私有的, lib下的文件為對(duì)外公開即外部可以使用的,我們可以看到該http庫(kù)下browser_client.dart, http.dart, io_client.dart, testing.dart是公開的API,我們拿其中一個(gè),這里我們拿http.dart文件看看
export 'src/base_client.dart';
export 'src/base_request.dart';
export 'src/base_response.dart';
export 'src/byte_stream.dart';
export 'src/client.dart';
export 'src/exception.dart';
export 'src/multipart_file.dart';
export 'src/multipart_request.dart';
export 'src/request.dart';
export 'src/response.dart';
export 'src/streamed_request.dart';
export 'src/streamed_response.dart';
可以看到export了幾個(gè)文件,即導(dǎo)出了這幾個(gè)文件,使外部這幾個(gè)文件的api,這時(shí)我們導(dǎo)入http來(lái)使用一下:
import 'package:http/http.dart' as http;

可以看到導(dǎo)入的幾個(gè)文件的類都可用了,那我們?cè)僬乙粋€(gè)沒(méi)export的文件來(lái)看看外部是否可用,我們拿browser_client.dart來(lái)看看,其中有一個(gè)類:

我們?cè)谕獠渴褂玫臅r(shí)候:

是會(huì)報(bào)錯(cuò)的,因?yàn)樵擃惒](méi)有export,即外部不可使用。
interface
已移除
switch & case & default
Dart中的switch語(yǔ)句可使用整數(shù),字符串或編譯時(shí)常量, 以下為使用字符串代碼示例:
var command = 'OPEN';
switch (command) {
case 'CLOSED':
executeClosed();
break;
case 'PENDING':
executePending();
break;
case 'APPROVED':
executeApproved();
break;
case 'DENIED':
executeDenied();
break;
case 'OPEN':
executeOpen();
break;
default: //表示其他值的條件
executeUnknown();
}
sync & yield
- sync 同步
- yield 生成
當(dāng)我們需要懶惰地(不需要很多手動(dòng)定義可迭代類時(shí)復(fù)雜的公式化代碼)生成一系列值時(shí),可以考慮使用生成器函數(shù), Dart內(nèi)置支持兩種生成器函數(shù):
- 同步生成器:返回一個(gè)Iterable對(duì)象
- 異步生成器:返回Stream對(duì)象
同步生成器:將函數(shù)體標(biāo)記為sync *,并使用yield語(yǔ)句來(lái)賦值,下面例子為返回 0-n 的迭代器:
Iterable<int> naturalsTo(int n) sync* {
print('start');
int k = 0;
while (k < n) yield k++;
print('end');
}
//使用
void main() {
var it = naturalsTo(5).iterator;
while(it.moveNext()) {
print(it.current);
}
}
//打印
start
value = 0
value = 1
value = 2
value = 3
value = 4
end
調(diào)用方法naturalsTo時(shí),會(huì)馬上返回Iterable,且可以獲取迭代器iterator,但是,在調(diào)用遍歷之前,naturalsTo函數(shù)主體并不會(huì)立即執(zhí)行,這里我們可以看到調(diào)用var it = naturalsTo(5).iterator的時(shí)候沒(méi)有任何打印,并且我們可以看到,在遍歷打印的時(shí)候,先調(diào)用start,當(dāng)把所有值打印完了,再打印end。說(shuō)明調(diào)用naturalsTo得到這個(gè)Iterable的iterator的時(shí)候,yield會(huì)在你每次調(diào)用moveNext進(jìn)行遍歷的時(shí)候產(chǎn)生一個(gè)值。當(dāng)函數(shù)運(yùn)行到y(tǒng)ield的時(shí)候,yield這里聲明一個(gè)求值表達(dá)式,返回值后,函數(shù)會(huì)在下一次moveNext的時(shí)候繼續(xù)執(zhí)行函數(shù)體。
異步生成器函數(shù),將函數(shù)體標(biāo)記為async *,并使用yield語(yǔ)句來(lái)傳遞值:
Stream<int> asynchronousNaturalsTo(int n) async* {
int k = 0;
while (k < n) yield k++;
}
//使用
void main() {
asynchronousNaturalsTo(5).listen((v) {
print(v);
});
}
//打印
start
0
1
2
3
4
end
使用異步生成器返回?cái)?shù)據(jù)流string,和sync*一樣,調(diào)用asynchronousNaturalsTo會(huì)立即返回Stream,但是只有在listen監(jiān)聽數(shù)據(jù)流的時(shí)候才會(huì)調(diào)用asynchronousNaturalsTo函數(shù)體,并且通過(guò)yield聲明求值表達(dá)式來(lái)計(jì)算對(duì)應(yīng)的值。
如果生成器內(nèi)部使用遞歸的話,可以使用yield *來(lái)提高其性能:
Iterable<int> naturalsDownFrom(int n) sync* {
if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}
//使用
void main() {
print(naturalsDownFrom(5));
}
//打印
(5, 4, 3, 2, 1)
naturalsDownFrom函數(shù)還是返回一個(gè)Iterable,當(dāng)參數(shù)為5時(shí),5 > 0時(shí),先執(zhí)行yield 5, 這時(shí)迭代器首先會(huì)產(chǎn)生一個(gè)值5,然后再通過(guò)yield*生成新的值,并且加到當(dāng)前迭代器中。
break & continue
跳出循環(huán)
while (true) {
if (shutDownRequested()) break;
processIncomingRequests();
}
跳到下一個(gè)循環(huán)迭代
or (int i = 0; i < candidates.length; i++) {
var candidate = candidates[i];
if (candidate.yearsExperience < 5) {
continue;
}
candidate.interview();
}
external
表示代碼的實(shí)現(xiàn)由外部提供,我們定義一個(gè)類:
class Object {
const Object();
external bool operator ==(other);
external int get hashCode;
external String toString();
}
//使用
void main() {
Object object = new Object();
print('to string = ${object.toString()}');
}
//打印
to string = null
//但是如果我們將toString去掉的話,則會(huì)打印
to string = Instance of 'Object' //dart中默認(rèn)的toString打印
external聲明了這些方法需要由外部去實(shí)現(xiàn),若外部沒(méi)實(shí)現(xiàn),則會(huì)返回null
library & part
使用library關(guān)鍵字可以定義一個(gè)庫(kù)的名字,我們這里自定義一個(gè)庫(kù)來(lái)說(shuō)明一下這兩個(gè)關(guān)鍵字:

這里分別有3個(gè)文件,我們看看:
main.dart
library main; //定義當(dāng)前庫(kù)的名字為main
import 'dart:math' as math;
//聲明以下兩個(gè)文件屬于main庫(kù)
part 'test/lib/liba.dart';
part 'test/lib/libb.dart';
class LibMain{
static int max(int a, int b) => math.max(a, b);
static String getParts() => LibA.TAG + ", " + LibB.TAG;
}
liba.dart
part of main; //聲明屬于main庫(kù)
class LibA{
static String TAG = 'liba';
}
libb.dart
part of main; //聲明屬于main庫(kù)
class LibB{
static String TAG = 'libb';
}
再導(dǎo)入main之后,
import 'lib/main.dart';
liba.dart和libb.dart中聲明的類外部可用:

part可以將庫(kù)拆分為多個(gè)Dart文件,但是建議盡量避免使用其來(lái)創(chuàng)建庫(kù),因?yàn)檫@樣會(huì)使代碼很難閱讀和修改。建議直接直接在lib/<包名> .dart下創(chuàng)建一個(gè)“main”庫(kù)文件,用一個(gè)main文件來(lái)管理所有公共API。
this
和Java中this相類似,用this關(guān)鍵字來(lái)引用當(dāng)前實(shí)例
factory
用來(lái)修飾構(gòu)造函數(shù),描述該構(gòu)造函數(shù)作為一個(gè)工廠構(gòu)造函數(shù)功能,在實(shí)現(xiàn)不用總是創(chuàng)建新實(shí)例的構(gòu)造函數(shù)的時(shí)候,可以使用factory關(guān)鍵字,例如下面例子中,可能從緩存中返回實(shí)例,或者子類的實(shí)例。
class Logger {
final String name;
bool mute = false;
//一個(gè)維護(hù)Logger類的map
static final Map<String, Logger> _cache =
<String, Logger>{};
//根據(jù)不同的name獲取對(duì)應(yīng)的Logger,
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
//一個(gè)內(nèi)部構(gòu)造函數(shù)
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
注意,使用factory修飾的構(gòu)造函數(shù)不能使用this,類似于在Java的static函數(shù)中,不能使用this
mixin & with & on
Dart 2.1中引入了對(duì)mixin關(guān)鍵字的支持, 我們可以看到官方的描述:Mixins是一種在多個(gè)類層次結(jié)構(gòu)中重用類代碼的方法。關(guān)鍵信息:
- 多個(gè)類層次結(jié)構(gòu)
- 重用類代碼
我這里只簡(jiǎn)單描述下該關(guān)鍵字的作用和使用方法:
- mixin字面意思為混入的意思,要使用mixin的話,需要使用with關(guān)鍵字,后跟一個(gè)或多個(gè)mixin的名稱, 可視為混入多個(gè)類
- 有時(shí)候我們需要?jiǎng)?chuàng)建一個(gè)類,這個(gè)類需要使用不同類的不同的方法的時(shí)候,就需要使用mixin方法,,因?yàn)镈art中只能繼承一個(gè)類,而且使用接口的話,必須在其他類也實(shí)現(xiàn)這個(gè)接口,下面我們使用我們看下下面的例子:
//程序員喜歡寫代碼
class Programmer{
code(){
print('I am a programmer, i like coding.');
}
}
//歌唱家喜歡唱歌
class Singer{
singing(){
print('I am a singer, i like singing.');
}
}
//既愛編碼,也愛唱歌
class Mixin with Programmer, Singer{
}
void main() {
Mixin mixin = Mixin();
mixin.code();
mixin.singing();
}
//打?。?I am a programmer, i like coding.
I am a musician, i like singing.
注意:這里類Programmer和Singer不能聲明構(gòu)造函數(shù)包括命名函數(shù):

當(dāng)我們使用mixin調(diào)用不同類相同接口結(jié)果會(huì)是怎樣呢,我們看下面代碼:
class A {
name(){
print('I am a student.');
}
}
class B{
name(){
print('I am a teacher.');
}
}
class AB with A, B{
}
class BA with B, A{
}
void main() {
new AB().name();
new BA().name();
}
//打?。?I am a teacher.
I am a student.
可以看到接口相同的情況這里是name,最終會(huì)調(diào)用with的最后一個(gè)類的接口。
如果我們需要限定,什么類才能被混入,可以使用mixin+on的方法限定:
//mixn定義了類Flutter要求只有實(shí)現(xiàn)Programmer類的才能被混入
mixin Flutter on Programmer{
flu(){
print('This is in flutter.');
}
}
//會(huì)如下面圖片報(bào)錯(cuò)
//class A with Flutter{
//}
//可以混入
class B extends Programmer with Flutter{
}
new B ().flu(); //打印This is in flutter.

最后,關(guān)于mixin更詳細(xì)的解釋可以參考:
throw
拋出異常:
throw FormatException('Expected at least 1 section');

也可以拋出任何任意對(duì)象異常:
throw 'Out of llamas!';

class Throw{
@override
String toString() {
return 'Are you ok?';
}
}
void main() {
throw new Throw();
}

try & catch & finally & on & rethrow
異常捕獲:
//普通使用
void main() {
try{
throw "You are wrong.";
}catch (e){
print('catch exception: '+e);
}
}
//打?。?catch exception: You are wrong.
使用on可以捕獲某種異常
class ExceptionA{
@override
String toString() {
return 'This is exception a.';
}
}
class ExceptionB{
@override
String toString() {
return 'This is exception b.';
}
}
throwCatchException(Object object){
try{
throw object;
} on ExceptionA{ //指定某種異常類
print("It's exception a.");
} on ExceptionB catch(e){ //指定某種異常類并獲取異常對(duì)象
print(e);
} on Exception catch (e){
print(e);
}
}
void main() {
throwCatchException(new ExceptionA());
throwCatchException(new ExceptionB());
throwCatchException(new Exception(''));
}
//打?。?It's exception a.
This is exception b.
Exception:
可以為catch()指定一個(gè)或兩個(gè)參數(shù), 第一個(gè)是拋出的異常對(duì)象,第二個(gè)是堆棧跟蹤(StackTrace對(duì)象):
void main() {
try{
throw 'This is a exception.';
}catch (e, s){
print('e ${e}');
print('s ${s}');
}
}
//打?。?e This is a exception.
s #0 main (file:///E:/flutter/projects/flutter/test/test.dart:5:5)
#1 _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:289:19)
#2 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
如果想異??蓚鞑? 使用rethrow接口
void misbehave() {
try {
dynamic foo = true;
print(foo++); // 運(yùn)行時(shí)出錯(cuò)
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; //允許調(diào)用者可以看到異常
}
}
void main() {
try {
misbehave();
} catch (e) {
print('main() finished handling ${e.runtimeType}.');
}
}
//打?。?misbehave() partially handled NoSuchMethodError.
main() finished handling NoSuchMethodError.
無(wú)論是否拋出異常,要確保某些代碼運(yùn)行,請(qǐng)使用finally子句。 如果沒(méi)有catch子句與異常匹配,則在finally子句運(yùn)行后拋出異常:
class ExceptionA{
@override
String toString() {
return 'This is exception a.';
}
}
class ExceptionB{
@override
String toString() {
return 'This is exception b.';
}
}
finallyMethod(){
print('finally method.');
}
void main() {
try {
throw new ExceptionA();
} on ExceptionB catch (e) {
print(e);
} finally{
finallyMethod();
}
}
//打印:
finally method.
Unhandled exception:
This is exception a.
#0 main (file:///E:/flutter/projects/flutter/test/test.dart:21:5)
#1 _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:289:19)
#2 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
false & true
為了表示布爾值,Dart有一個(gè)名為bool的類型, 只有兩個(gè)對(duì)象具有bool類型: true和false,它們都是編譯時(shí)常量
new
創(chuàng)建類實(shí)例
class
聲明一個(gè)類
final & const
final聲明一個(gè)變量只能初始化一次,和java用法相同
const聲明一個(gè)是編譯時(shí)常量的變量, 常量變量不能進(jìn)行賦值,如果const變量在類級(jí)別,則將其標(biāo)記為static const。
當(dāng)我們想讓一個(gè)變量不被改變,可以聲明為const變量。
typedef
typedef用于給函數(shù)類型指定名稱,因?yàn)樵贒art中,函數(shù)也是一個(gè)對(duì)象,通常用Function泛指所有函數(shù),我們來(lái)看一下下面的例子(沒(méi)有使用函數(shù)別名):
class SortedCollection {
Function compare;
//這里需要傳遞一個(gè)返回值為int,參數(shù)為(Object, Object)的函數(shù)
SortedCollection(int f(Object a, Object b)) {
compare = f;
}
}
//一個(gè)返回值為int,參數(shù)為(Object, Object)的函數(shù)
int sort(Object a, Object b) => 0;
void main() {
SortedCollection coll = SortedCollection(sort);
// 我們都知道compare是一個(gè)函數(shù)
// 但是我們知道它是什么類型的函數(shù)嗎,意味著我們只知道它是一個(gè)函數(shù),但是是什么類型的函數(shù)我們不知道
assert(coll.compare is Function); // 這里毫無(wú)疑問(wèn)是true, 即不會(huì)中斷執(zhí)行
}
我們可以用typedef來(lái)聲明一個(gè)函數(shù)類型:
//定義一個(gè)函數(shù)類型為compare,其類型為
typedef Compare = int Function(Object a, Object b);
class SortedCollection {
Compare compare;
SortedCollection(this.compare);
}
//一個(gè)返回值為int,參數(shù)為(Object, Object)的函數(shù)即類型為Compare的函數(shù)
int sort(Object a, Object b) => 0;
void main() {
SortedCollection coll = SortedCollection(sort);
assert(coll.compare is Function); //True
assert(coll.compare is Compare); //True
}
目前typedef只能用于聲明函數(shù)類型,
operator
如果你想定義一個(gè)Vector類(向量類),可以使用以下運(yùn)算符:
| < | + | | | [] |
| > | / | ^ | []= |
| <= | ~/ | & | ~ |
| >= | * | << | == |
| - | % | >> |
下面為一個(gè)覆蓋+和 - 運(yùn)算符的類的示例:
class Vector {
final int x, y;
Vector(this.x, this.y);
Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
// Operator == and hashCode not shown. For details, see note below.
// ···
}
void main() {
final v = Vector(2, 3);
final w = Vector(2, 3);
final vw = v + w;
final ww = v - w;
print('vw -> (${vw.x}, ${vw.y})');
print('ww -> (${ww.x}, ${ww.y})');
}
//打?。?vw -> (4, 6)
ww -> (0, 0)
var
使用var聲明一個(gè)變量但是不指定其類型
var name = 'Bob'; //聲明一個(gè)變量為字符串變量
但是一旦聲明賦值了為一個(gè)類型候,不能再分配給另一個(gè)類型

covariant
我們?cè)诶^承一個(gè)類的時(shí)候,在重構(gòu)一個(gè)方法時(shí),強(qiáng)制將其參數(shù)由父類縮窄成其子類的話,會(huì)提示錯(cuò)誤,例子:
//定義一個(gè)Animal類,其函數(shù)chase參數(shù)為Animal
class Animal {
void chase(Animal x) {}
}
class Mouse extends Animal {
getName(){
return 'mouse';
}
}
class Cat extends Animal {
//強(qiáng)制將chase函數(shù)的Animal參數(shù)縮窄成Mouse
void chase(Mouse mouse) {
print('cat chase ${mouse.getName()}');
}
}
//報(bào)錯(cuò), 提示重寫類型不匹配
test/test.dart:12:20: Error: The parameter 'mouse' of the method 'Cat::chase' has type #lib1::Mouse, which does not match the corresponding type in the overridden method (#lib1::Animal).
Change to a supertype of #lib1::Animal (or, for a covariant parameter, a subtype).
void chase(Mouse mouse) {
^
test/test.dart:2:8: Context: This is the overridden method ('chase').
void chase(Animal x) {}
^
使用covariant關(guān)鍵字后:
class Animal {
void chase(Animal x) {}
}
class Mouse extends Animal {
getName(){
return 'mouse';
}
}
class Cat extends Animal {
void chase(covariant Mouse mouse) {
print('cat chase ${mouse.getName()}');
}
}
void main(){
new Cat().chase(new Mouse());
}
//打印
cat chase mouse
covariant字義為協(xié)變,即我和編譯器協(xié)商,這個(gè)參數(shù)縮窄變化是我故意這樣做的,你別拋異常了。
Function
Dart是一種真正的面向?qū)ο笳Z(yǔ)言,因此即使是函數(shù)也是對(duì)象并且具有類型Function。 這意味著函數(shù)可以分配給變量或作為參數(shù)傳遞給其他函數(shù)。
//定義一個(gè)add函數(shù)
int add(int a, int b) => a+b;
handle(Function function){
print('handle: ${function(1, 2)}'); //打印function的結(jié)果
}
void main(){
handle(add); //調(diào)用handle并傳遞add函數(shù)
}
//打印
handle: 3
void
在Dart 1中,void僅可用作函數(shù)的返回類型(例如void main()),但在Dart 2中它已被推廣,并且可在其他地方使用, 例如Future <void>
void類型不能用于任何東西,且將某些東西分配給void類型是無(wú)效的:
void foo() {}
void main() {
var bar = foo(); // 無(wú)效
}
The expression here has a type of 'void', and therefore cannot be used. -> 此表達(dá)式的類型為“void”,無(wú)法使用

在函數(shù)中,表示該函數(shù)無(wú)需返回值。
在實(shí)踐中,一般使用void來(lái)表示“任何我不關(guān)心元素”,或者更常見的是,表示“省略”,例如在Future <void>或Stream <void>中。
get & set
在Java中,getter和setter應(yīng)該是蠻令我們頭疼,如果一些類的屬性足夠多的話,提供getter和setter接口后,文件很輕松可以達(dá)到成千上百行。但是在Dart中,提供了set和get關(guān)鍵子來(lái)提供對(duì)象屬性的讀寫訪問(wèn)權(quán)限。
class Rectangle {
num left, top, width, height;
Rectangle(this.left, this.top, this.width, this.height);
//定義兩個(gè)可計(jì)算的屬性right 和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;
}
void main() {
var rect = Rectangle(3, 4, 20, 15);
print('right: ${rect.right}');
rect.right = 100;
print('right: ${rect.right}');
print('bottom: ${rect.bottom}');
rect.bottom = 120;
print('bottom: ${rect.bottom}');
}
//打?。?right: 23
right: 100
bottom: 19
bottom: 120
在Dart中,使用get和set實(shí)現(xiàn)getter和setter功能,是不是簡(jiǎn)潔多了呢
使用get和set后,我們可以從實(shí)例變量開始,在get/set的方法中用方法封裝,而無(wú)需更改外部調(diào)用的代碼。
while & do while
while: 在循環(huán)執(zhí)行之前計(jì)算條件
while (!isDone()) {
doSomething();
}
do-while: 在循環(huán)開始執(zhí)行后計(jì)算條件
do {
printLine();
} while (!atEndOfPage());
deferred
deferred用于聲明一個(gè)延遲加載一個(gè)庫(kù),通常叫懶加載。允許你只有在需要使用該庫(kù)的時(shí)候,再加載該庫(kù)。
//文件calculate.dart
class Calculate{
static String name = "Cal";
static printf(String s){
print('cal: $s');
}
int add(int a, int b) => a + b;
}
//文件test.dart
import 'calculate.dart' deferred as cal; //聲明該庫(kù)會(huì)延遲加載且命名為cal
void main() {
print('1');
greet();
print('2');
print('3');
}
//異步加載庫(kù)calculate.dart
//加載完畢后再進(jìn)行操作
Future greet() async {
await cal.loadLibrary();
print('cal name: ${cal.Calculate.name}');
print('add(1, 2) = ${new cal.Calculate().add(1, 2)}');
cal.Calculate.printf('ss');
}
//打印:
1
2
3
cal name: Cal
add(1, 2) = 3
cal: ss
return
用于在函數(shù)中返回一個(gè)值
