Flutter--Dart語法小記

可選參數

Dart方法有兩種類型的參數:必需的和可選的。必需的咱們通常都知道,這裏主要分析可選參數。算法

若是同時包含可選參數和必需參數,必需的參數在參數列表前面, 可選數在後面。bash

可選參數能夠有一個默認值,當默認值在調用者沒有指定值時使用。這一點和kotlin的語法很像。其次可選參數具體可分爲:ide

  • Optional named parameters(可選命名參數)
  • Optional positional parameters(可選位置參數)

可選命名參數

在方法參數中,使用"{}"包圍的參數屬於可選命名參數,好比函數

void _buildThree(int num, {String name, int range}) {
    
  }
複製代碼

能夠爲可選參數添加默認值,好比:工具

void _buildThree(int num, {String name, int range = 10}) {

  }
複製代碼

調用包含可選命名參數的方法時,須要使用paramName:value的形式指定爲哪一個可選參數賦值,好比:學習

_buildThree(10,range: 1);
複製代碼

可選位置參數

在方法參數中,使用"[]"包圍的參數屬於可選位置參數,好比測試

void _buildHouse(int num, [String where, int range]) {

  }
  
  void _buildHouseAndDefaultValue(int num, [String where = 'Shanghai', int range]) {

  }
複製代碼

調用包含可選位置參數的方法時,無需使用paramName:value的形式,由於 可選位置參數是位置,若是想指定某個位置上的參數值,則必須前面位置的已經有值,即便前面的值存在默認值。 好比:ui

_buildHouse(10,10); //不可行的
    
    _buildHouse(10,'shenzhen',10); //可行的
    
    _buildHouseAndDefaultValue(10,10); //不可行的
    
    _buildHouseAndDefaultValue(10,'shenzhen',10); //可行的
    
    
複製代碼

這裏特地使用兩個不一樣類型的可選參數做爲示例,若是先後可選參數爲相同類型,則會出現異常結果,而且只有在發生後纔會注意到。因此這一點要特別注意。好比如下示例,假如本意是想賦值給age,但結果將會差強人意this

void _buildHouse(int num, [int range , int age]) {
  print('range : $range age : $age');
}

void main() {
  _buildHouse(10,10);
}

輸出:

range :  10  age : null
複製代碼

Mixins與with關鍵字

Dart和Java同樣只支持單繼承。並且Dart中沒有和Java同樣提供Interface字段去聲明一個接口,可是也有抽象類。spa

若是想使用和Java接口同樣的功能可使用Mixinsimplements兩種方式,分別解釋下兩種方式:

  • Mixins : 指可以將另外一個或多個類的功能添加到您本身的類中,而無需繼承這些類。
  • implements : 將一個類做爲接口使用
class A {
  void a() {
    print('a');
  }
}

class B implements A {
  @override
  void a() {
    print('override a');
  }
}

class C {
  void c() {
    print('c');
  }
}

class E {
  String e = 'eeee';
}

class D extends A with C, E {
  void c() {
    print('c is D');
  }

  void d() {
    c();
  }
}
複製代碼

首先看B implements A,因此此時A相對於B來講就是一個接口,因此他要實現B中的方法。換句話說,Dart每一個類都是接口

而後看D extends A with C ,D繼承於A,因爲單繼承特性,這個時候D不能再使用extends關鍵字繼承其餘類,可是可使用with關鍵字摺疊其餘類以實現代碼重用。當屬性和方法重複時,以當前類爲準。 好比上面例子調用Dc()方法打印的是 c is D

Typedefs

在學習Flutter的過程當中用到了ValueChange這個方法,是用typedef修飾的一個方法。查閱了一番資料,記錄下對Typedefs的理解。

先看看官網的解釋,我並無看明白這個到底有什麼用,能夠作什麼事。

說下本身的我的理解。首先須要明確的一點是在Dart中,方法是一等對象。能夠把方法當作參數調用另一個方法。 typedef 本質上爲 一個方法簽名提供了一個別名。官網上介紹TypeDef的時候有一句話說道:"If we change the code to use explicit names and retain type information" ,使用typedef會保留方法的類型信息。以官網的例子說明

class SortedCollection {
  Function compare;

  SortedCollection(int f(Object a, Object b)) {
    compare = f;
  }
}

// Initial, broken implementation.
int sort(Object a, Object b) => 0;

void main() {
  SortedCollection coll = SortedCollection(sort);

  // All we know is that compare is a function,
  // but what type of function?
  assert(coll.compare is Function);
}
複製代碼

當把 f 賦值給 compare 的時候, 類型信息丟失了。 f 的類型是 (Object, Object) → int (這裏 → 表明返回值類型)。咱們不能使用coll.compare is int f(Object a, Object b)判斷,咱們只知道該類型是一個 Function。而使用typedef,至關於給方法貼了一個類型標籤

我在Effective Dart中看到一條規則說到: 若是須要的只是一個回調函數,使用方法便可。 若是你定義了一個類,裏面只有一個名字無心義的函數, 例如 call 或者 invoke, 這種狀況最好用方法替代;

//good
typedef Predicate<E> = bool Function(E element);

//bad
abstract class Predicate<E> {
  bool test(E element);
}
複製代碼

前面提到的ValueChange這個方法就是做爲回調函數使用,具體細節能夠參考The parent widget manages the widget’s state

Generics泛型

Dart中關於泛型的使用和Java相差不大,可是重要的一點區別是:Java 中泛型信息是編譯時的,泛型類型信息在運行時被擦除。而Dart 的泛型類型是固化的,在運行時有也 能夠判斷具體的類型。 好比如下代碼再Java中是行不通的,但在Dart中是可行的

var names = new List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // true

複製代碼

注意 is 表達式只是判斷集合的類型,而不是集合裏面具體對象的類型。

Import

import 必須參數爲庫 的 URI。 對於內置的庫,URI 使用特殊的 dart: scheme。 對於其餘的庫,你可使用文件系統路徑或者 package: schemepackage: scheme 指定的庫經過包管理器來提供, 例如 pub 工具

import 'dart:io';
import 'package:mylib/mylib.dart';
import 'package:utils/utils.dart';
複製代碼

若是導入的多個庫具備衝突的標識符,可使用庫的前綴來區分

import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// ...
Element element1 = new Element();           // 使用lib1的Element.
lib2.Element element2 = new lib2.Element(); // 使用lib2的Element..
複製代碼

若是隻使用庫的一部分功能,則能夠選擇須要導入的內容。

// 只導入foo.
import 'package:lib1/lib1.dart' show foo;

// 導入除了foo之外的
import 'package:lib2/lib2.dart' hide foo;
複製代碼

Lazily loading a library

Deferred loading可讓應用在須要的時候再 加載庫。 下面是一些使用延遲加載庫的場景:

  • 減小 APP 的啓動時間。
  • 執行 A/B 測試,例如 嘗試各類算法的 不一樣實現。
  • 加載不多使用的功能,例如可選的屏幕和對話框。

要延遲加載一個庫,須要先使用 deferred as 來 導入:

import 'package:deferred/hello.dart' deferred as hello;
複製代碼

使用的時候,使用庫標識符調用 loadLibrary() 函數來加載庫。注意:調用 loadLibrary() 該庫只是載入一次

使用延遲加載庫的時候,請注意一下問題:

  1. 延遲加載庫的常量在導入的時候是不可用的。 只有當庫加載完畢的時候,庫中常量纔可使用。
  2. 在導入文件的時候沒法使用延遲庫中的類型。 若是你須要使用類型,則考慮把接口類型移動到另一個庫中, 讓兩個庫都分別導入這個接口庫。
  3. Dart 隱含的把 loadLibrary() 函數導入到使用 deferred as 的命名空間 中。 loadLibrary() 方法返回一個 Future

註解

Dart默認包含全部代碼均可以使用的三個註解: @deprecated@override、 和 @proxy

  • 使用 @deprecated 註解表示函數被啓用
  • 使用 @override 註解來 代表你的函數是想覆寫超類的一個函數
  • 使用 @proxy 註解來避免警告信息

能夠自定義元數據註解,與Java不一樣的是無需使用 @interface 關鍵字進行定義,只需使用普通的 class 方式聲明,如

library todo;

class todo {
  final String who;
  final String what;

  const todo(this.who, this.what);
}
複製代碼
import 'todo.dart';

@todo('seth', 'make this do something')
void doSomething() {
  print('do something');
}
複製代碼
相關文章
相關標籤/搜索