開發(fā)中總結(jié)的dart相關(guān)的技巧

特意給大家?guī)砦以陂_發(fā)中總結(jié)的dart相關(guān)的技巧

1. 你知道嗎办悟?Dart 支持字符串乘法尘奏。

這是一個簡單的程序,顯示如何使用字符串乘法打印圣誕樹:

void main() {
  for (var i = 1; i <= 5; i++) {
    print('??' * i);
  }
}
// Output:
// ??
// ????
// ??????
// ????????
// ??????????

是不是很酷病蛉???

您可以使用它來檢查長字符串如何適合Text小部件:

Text('You have pushed the button this many times:' * 5)

2.需要同時執(zhí)行多個Future嗎炫加?使用 Future.wait。

考慮這個模擬 API 類铺然,它告訴我們最新的 COVID 病例數(shù):

// Mock API class
class CovidAPI {
  Future<int> getCases() => Future.value(1000);
  Future<int> getRecovered() => Future.value(100);
  Future<int> getDeaths() => Future.value(10);
}

要同時執(zhí)行所有這些futures俗孝,請使用Future.wait. 這需要一個**列表或 futures and returns a future of lists:

final api = CovidAPI();
final values = await Future.wait([
    api.getCases(),
    api.getRecovered(),
    api.getDeaths(),
]);
print(values); // [1000, 100, 10]

This is ideal when the futures are independent, and they don't need to execute sequentially.

3. 在 Dart 類中實現(xiàn)“調(diào)用”方法,使它們像函數(shù)一樣可調(diào)用魄健。

這是一個示例PasswordValidator類:

class PasswordValidator {
  bool call(String password) {
    return password.length > 10;
  }
}

因為該方法名為call赋铝,我們可以聲明一個類實例并將其用作方法:

final validator = PasswordValidator();
// can use it like this:
validator('test');
validator('test1234');
// no need to use it like this:
validator.call('not-so-frozen-arctic');

4. 需要調(diào)用回調(diào)但前提是它不為空?使用“?.call()”語法沽瘦。

假設(shè)我們有一個自定義小部件類革骨,它應(yīng)該onDragCompleted在發(fā)生特定事件時調(diào)用回調(diào):

class CustomDraggable extends StatelessWidget {
  const CustomDraggable({Key key, this.onDragCompleted}) : super(key: key);
  final VoidCallback? onDragCompleted;

  void _dragComplete() {
    // TODO: Implement me
  }
  @override
  Widget build(BuildContext context) {/*...*/}
}

要調(diào)用回調(diào),我們可以編寫以下代碼:

  void _dragComplete() {
    if (onDragCompleted != null) {
      onDragCompleted();
    }
  }

但是有一個更簡單的方法(注意使用?.):

  Future<void> _dragComplete() async {
    onDragCompleted?.call();
  }

5. 使用匿名函數(shù)和函數(shù)作為參數(shù)

在 Dart 中其垄,函數(shù)是一等公民,可以作為參數(shù)傳遞給其他函數(shù)卤橄。

下面是一些定義匿名函數(shù)并將其分配給sayHi變量的代碼:

void main() {
  final sayHi = (name) => 'Hi, $name';
  welcome(sayHi, 'Andrea');
}

void welcome(String Function(String) greet,
             String name) {
  print(greet(name));
  print('Welcome to this course');
}

然后sayHi傳遞給一個welcome函數(shù)寝受,該函數(shù)接受一個Function參數(shù)并使用它來迎接用戶侦副。

String Function(String)是一個函數(shù)類型,它接受一個String參數(shù)并返回一個String. 因為上面的匿名函數(shù)具有相同的簽名寸齐,它可以直接作為參數(shù)傳遞,也可以通過變量傳遞sayHi婉刀。


使用功能等運營商時,這種編碼風格是常見的mapwherereduce蔫浆。

例如,這是一個計算數(shù)字平方的簡單函數(shù):

int square(int value) {
  // just a simple example
  // could be a complex function with a lot of code
  return value * value;
}

給定一個值列表姐叁,我們可以映射它們以獲得平方:

const values = [1, 2, 3];

values.map(square).toList();

這里我們square作為參數(shù)傳遞瓦盛,因為它的簽名正是 map 操作符所期望的。這意味著我們不需要用匿名函數(shù)擴展它:

values.map((value) => square(value)).toList();

6. 您可以使用 collection-if 和 spreads 與lists, sets AND maps

當您將 UI 作為代碼編寫時外潜,Collection-if 和 spreads 非常有用原环。

但是您知道您也可以將它們與maps一起使用嗎?

考慮這個例子:

const addRatings = true;
const restaurant = {
  'name' : 'Pizza Mario',
  'cuisine': 'Italian',
  if (addRatings) ...{
    'avgRating': 4.3,
    'numRatings': 5,
  }
};

這里我們聲明一個restaurantmaps处窥,只添加avgRatingnumRatings鍵值對嘱吗,如果addRatingstrue。因為我們要添加多個鍵值對滔驾,所以我們需要使用擴展運算符 ( ...)谒麦。

7. 需要以空安全的方式遍歷map嗎?使用.entries

假設(shè)你有map:

const timeSpent = <String, double>{
  'Blogging': 10.5,
  'YouTube': 30.5,
  'Courses': 75.2,
};

以下是如何編寫循環(huán)以使用所有鍵值對運行一些代碼:

for (var entry in timeSpent.entries) {
  // do something with keys and values
  print('${entry.key}: ${entry.value}');
}

通過迭代entries變量哆致,您可以以空安全的方式訪問所有鍵值對绕德。

這比這更簡潔,更不容易出錯:

for (var key in timeSpent.keys) {
  final value = timeSpent[key]!;
  print('$key: $value');
}

上面的代碼!在讀取值時需要使用斷言運算符 ( )沽瞭,因為 Dart 不能保證給定鍵的值存在迁匠。

8. 使用命名構(gòu)造函數(shù)和初始化列表以獲得更符合人體工程學的 API。

假設(shè)您要聲明一個表示溫度值的類驹溃。

你可以讓你的類API明確支持兩個攝氏和華氏兩種命名的構(gòu)造函數(shù):

class Temperature {
  Temperature.celsius(this.celsius);
  Temperature.fahrenheit(double fahrenheit)
    : celsius = (fahrenheit - 32) / 1.8;
  double celsius;
}

這個類只需要一個存儲變量來表示溫度城丧,并使用初始化列表將華氏溫度轉(zhuǎn)換為攝氏溫度。

這意味著您可以像這樣聲明溫度值:

final temp1 = Temperature.celsius(30);
final temp2 = Temperature.fahrenheit(90);

9. getter 和 setter

Temperature上面的類中豌鹤,celsius被聲明為存儲變量亡哄。

但是用戶可能更喜歡以華氏度獲取設(shè)置溫度。

這可以使用 getter 和 setter 輕松完成布疙,它們允許您定義計算變量蚊惯。這是更新的課程:

class Temperature {
  Temperature.celsius(this.celsius);
  Temperature.fahrenheit(double fahrenheit)
    : celsius = (fahrenheit - 32) / 1.8;
  double celsius;
  double get fahrenheit
    => celsius * 1.8 + 32;
  set fahrenheit(double fahrenheit)
    => celsius = (fahrenheit - 32) / 1.8;
}

這使得使用華氏度或攝氏度輕松獲取或設(shè)置溫度:

final temp1 = Temperature.celsius(30);
print(temp1.fahrenheit);
final temp2 = Temperature.fahrenheit(90);
temp2.celsius = 28;

底線:使用命名構(gòu)造函數(shù)、getter 和 setter 來改進類的設(shè)計灵临。

10. 對未使用的函數(shù)參數(shù)使用下劃線

在 Flutter 中截型,我們經(jīng)常使用帶有函數(shù)參數(shù)的小部件。一個常見的例子是ListView.builder

class MyListView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemBuilder: (context, index) => ListTile(
        title: Text('all the same'),
      ),
      itemCount: 10,
    );
  }
}

在這種情況下儒溉,我們不使用(context, index)的參數(shù)itemBuilder宦焦。所以我們可以用下劃線代替它們:

ListView.builder(
  itemBuilder: (_, __) => ListTile(
    title: Text('all the same'),
  ),
  itemCount: 10,
)

注意:這兩個參數(shù)是不同的 (___),因為它們是單獨的標識符

11. 需要一個只能實例化一次的類(又名單例)波闹?使用帶有私有構(gòu)造函數(shù)的靜態(tài)實例變量酝豪。

單例最重要的特性是整個程序中只能有一個它的實例。這對于建模文件系統(tǒng)之類的東西很有用精堕。

// file_system.dart
class FileSystem {
  FileSystem._();
  static final instance = FileSystem._();
}

要在 Dart 中創(chuàng)建單例孵淘,您可以聲明一個命名構(gòu)造函數(shù)并使用_語法將其設(shè)為私有。

然后歹篓,您可以使用它來創(chuàng)建類的一個靜態(tài)最終實例瘫证。

因此,其他文件中的任何代碼都只能通過instance變量訪問此類:

// some_other_file.dart
final fs = FileSystem.instance;
// do something with fs

注意:如果您不小心滋捶,final可能會導(dǎo)致許多問題痛悯。在使用它們之前,請確保您了解它們的缺點重窟。

12. 需要收集獨特的set载萌?使用集合而不是列表。

Dart 中最常用的集合類型是List.

但是列表可以有重復(fù)的項目巡扇,有時這不是我們想要的:

const citiesList = [
  'London',
  'Paris',
  'Rome',
  'London',
];

我們可以Set在需要一組唯一值時使用 a (請注意 的使用final):

// set is final, compiles
final citiesSet = {
  'London',
  'Paris',
  'Rome',
  'London', // Two elements in a set literal shouldn't be equal
};

上面的代碼生成一個警告扭仁,因為London被包含了兩次。如果我們嘗試對constset執(zhí)行相同的操作厅翔,則會收到錯誤并且我們的代碼無法編譯:

// set is const, doesn't compile
const citiesSet = {
  'London',
  'Paris',
  'Rome',
  'London', // Two elements in a constant set literal can't be equal
};

當我們與臺合作乖坠,我們能夠獲得有用的API,如union刀闷,differenceintersection

citiesSet.union({'Delhi', 'Moscow'});
citiesSet.difference({'London', 'Madrid'});
citiesSet.intersection({'London', 'Berlin'});

底線:當你創(chuàng)建一個集合時熊泵,問問自己你是否希望它的項目是獨一無二的,并考慮使用一個集合甸昏。

13.如何使用try顽分、on、catch施蜜、rethrow卒蘸、finally

try并且catch在使用基于 Future 的 API 時非常理想,如果出現(xiàn)問題翻默,這些 API 可能會引發(fā)異常缸沃。

這是一個完整的示例,展示了如何充分利用它們:

Future<void> printWeather() async {
  try {
    final api = WeatherApiClient();
    final weather = await api.getWeather('London');
    print(weather);
  } on SocketException catch (_) {
    print('Could not fetch data. Check your connection.');
  } on WeatherApiException catch (e) {
    print(e.message);
  } catch (e, st) {
    print('Error: $e\nStack trace: $st');
    rethrow;
  } finally {
    print('Done');
  }
}

一些注意事項:

  • 您可以添加多個on子句來處理不同類型的異常修械。
  • 您可以使用回退catch子句來處理與上述任何類型都不匹配的所有異常趾牧。
  • 您可以使用rethrow語句將當前異常向上拋出調(diào)用堆棧,同時保留堆棧跟蹤肯污。
  • 您可以使用finallyFuture完成后運行一些代碼翘单,無論它是成功還是失敗梯皿。

如果您正在使用或設(shè)計一些基于 Future 的 API,請確保根據(jù)需要處理異常。

14. 常見的 Future 構(gòu)造函數(shù)

DartFuture類帶有一些方便的工廠構(gòu)造函數(shù):Future.delayed,Future.valueFuture.error剂桥。

我們可以Future.delayed用來創(chuàng)建一個Future等待一定延遲的忠烛。第二個參數(shù)是一個(可選的)匿名函數(shù),你可以用它來完成一個值或拋出一個錯誤:

await Future.delayed(Duration(seconds: 2), () => 'Latte');

但有時我們想創(chuàng)建一個Future立即完成的:

await Future.value('Cappuccino');
await Future.error(Exception('Out of milk'));

我們可以用Future.value一個值來成功完成美尸,或者Future.error用一個錯誤來完成师坎。

您可以使用這些構(gòu)造函數(shù)來模擬來自基于 Future 的 API 的響應(yīng)。這在您的測試代碼中編寫模擬類時很有用堪滨。

15. 通用流構(gòu)造器

Stream 類還帶有一些方便的構(gòu)造函數(shù)胯陋。以下是最常見的:

Stream.fromIterable([1, 2, 3]);
Stream.value(10);
Stream.empty();
Stream.error(Exception('something went wrong'));
Stream.fromFuture(Future.delayed(Duration(seconds: 1), () => 42));
Stream.periodic(Duration(seconds: 1), (index) => index);
  • 用于從值列表Stream.fromIterable創(chuàng)建一個Stream
  • 使用Stream.value袱箱,如果你只有一個值遏乔。
  • 用于Stream.empty創(chuàng)建空流。
  • 用于Stream.error創(chuàng)建包含錯誤值的流发笔。
  • 用于Stream.fromFuture創(chuàng)建僅包含一個值的流盟萨,該值將在未來完成時可用。
  • 用于Stream.periodic創(chuàng)建周期性的事件流了讨。您可以將 a 指定Duration為事件之間的時間間隔捻激,并指定一個匿名函數(shù)來生成給定其在流中的索引的每個值。

16. 同步和異步生成器

在 Dart 中前计,我們可以將同步生成器定義為一個返回 的函數(shù)Iterable

Iterable<int> count(int n) sync* {
  for (var i = 1; i <= n; i++) {
    yield i;
  }
}

這使用sync*語法胞谭。在函數(shù)內(nèi)部,我們可以“生成”或yield多個值残炮。這些將Iterable在函數(shù)完成時返回韭赘。


另一方面,異步生成器是一個返回 a 的函數(shù)Stream

Stream<int> countStream(int n) async* {
  for (var i = 1; i <= n; i++) {
    yield i;
  }
}

這使用此async*語法势就。在函數(shù)內(nèi)部泉瞻,我們可以yield像在同步情況下一樣取值。

但是如果我們愿意苞冯,我們可以使用await基于 Future 的 API袖牙,因為這是一個異步生成器:

Stream<int> countStream(int n) async* {
  for (var i = 1; i <= n; i++) {
    // dummy delay - this could be a network request
    await Future.delayed(Duration(seconds: 1));
    yield i;
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市舅锄,隨后出現(xiàn)的幾起案子鞭达,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件畴蹭,死亡現(xiàn)場離奇詭異坦仍,居然都是意外死亡,警方通過查閱死者的電腦和手機叨襟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門繁扎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人糊闽,你說我怎么就攤上這事梳玫。” “怎么了右犹?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵提澎,是天一觀的道長。 經(jīng)常有香客問我念链,道長盼忌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任掂墓,我火速辦了婚禮碴犬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘梆暮。我一直安慰自己服协,他們只是感情好,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布啦粹。 她就那樣靜靜地躺著偿荷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪唠椭。 梳的紋絲不亂的頭發(fā)上跳纳,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機與錄音贪嫂,去河邊找鬼寺庄。 笑死,一個胖子當著我的面吹牛力崇,可吹牛的內(nèi)容都是我干的斗塘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼亮靴,長吁一口氣:“原來是場噩夢啊……” “哼馍盟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起茧吊,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤贞岭,失蹤者是張志新(化名)和其女友劉穎八毯,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瞄桨,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡话速,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了芯侥。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尿孔。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖筹麸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情雏婶,我是刑警寧澤物赶,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站留晚,受9級特大地震影響酵紫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜错维,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一奖地、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赋焕,春花似錦参歹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至侨嘀,卻和暖如春臭挽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背咬腕。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工欢峰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人涨共。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓纽帖,卻偏偏與公主長得像,于是被迫代替她去往敵國和親举反。 傳聞我的和親對象是個殘疾皇子抛计,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容