Flutter學(xué)習(xí)之Dart語(yǔ)言基礎(chǔ)(關(guān)鍵字)

Flutter日漸火爆,因此在進(jìn)行Flutter學(xué)習(xí)前先學(xué)習(xí)一些其所使用的開發(fā)語(yǔ)言dart的基礎(chǔ),這篇文章主要學(xué)習(xí)了

  1. Dart的基礎(chǔ)代碼示例
  2. Dart的概念
  3. 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

export.png

我們可以看到該包下面有一個(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;
image.png

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


client.png

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


error.png

是會(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)鍵字:


library.png

這里分別有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中聲明的類外部可用:


library.png

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ù):


mixin.png

當(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.
mixin.png

最后,關(guān)于mixin更詳細(xì)的解釋可以參考:

throw

拋出異常:

throw FormatException('Expected at least 1 section');
throw.png

也可以拋出任何任意對(duì)象異常:

throw 'Out of llamas!';
throw.png
class Throw{
  @override
  String toString() {
    return 'Are you ok?';
  }
}

void main() {
  throw new Throw();
}
throw.png
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è)類型


var.png
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ú)法使用

void.png

在函數(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è)值

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容