[譯] 類型及其在參數中的應用:利用 Dart 特性優化代碼

類型及其在參數中的應用:利用 Dart 特性優化代碼

本篇教程將會介紹 Dart 語言的一些基礎特性,以及如何將其應用於代碼中。前端

正確的使用這些特性,可以讓你的代碼更加整潔、輕量,而且健壯。android

1. 類型推斷

Dart 編譯器可以在變量初始化的時候自動推斷它的類型,因此咱們也就沒必要聲明變量的類型。ios

在代碼應用中,也就是咱們能夠將這樣的代碼:git

String name = 'Andrea';
int age = 35;
double height = 1.84;
複製代碼

轉化爲:程序員

var name = 'Andrea';
var age = 35;
var height = 1.84;
複製代碼

這段代碼之因此能生效,是由於 Dart 能夠從表達式右邊的值推斷出變量的類型。github

咱們能夠像這樣聲明變量:編程

var x;
x = 15;
x = 'hello';
複製代碼

在這個例子中,x 聲明在前,初始化在後。後端

此時它的類型是動態的,即 dynamic,這意味着,它能夠被多個表達式賦值爲不一樣的類型。安全

小結less

  • 當使用 var 的時候,只要變量的聲明和初始化是同時完成的,那麼 Dart 將能正確的推斷出變量類型。

2. final 和 const

當咱們使用 var 來聲明變量的時候,這個變量能夠被屢次賦值:

var name = 'Andrea';
name = 'Bob';
複製代碼

也就是說:

使用 var 意味着能夠屢次賦值

可是若是咱們使用了 final,就不能給變量屢次賦值了:

final name = 'Andrea';
name = 'Bob'; // 'name' 是一個 final 類型的變量,不能夠被再次賦值
複製代碼

final 的應用

在 widget 類中,很常見使用 final 聲明的屬性。例如:

class PlaceholderContent extends StatelessWidget {
  const PlaceholderContent({
    this.title,
    this.message,
  });
  final String title;
  final String message;
  
  // TODO:實現構建方法
}
複製代碼

在這段代碼中,titlemessage 在這個 widget 內是不能夠被修改的,由於:

使用 final 意味着只能一次賦值

因此,使用 varfinal 的區別就是是否容許屢次或只能一次賦值。如今咱們再來看看 const

const

const 可以定義編譯時常量

const 用來定義硬編碼值,例如顏色、字體大小和圖標等。

同時咱們也能夠在定義 widget 類的時候使用 const 構建函數。

這是徹底可行的,由於全部 widget 內部的變量和方法都是編譯時常量。例如:

class PlaceholderContent extends StatelessWidget {
  const PlaceholderContent({
    this.title,
    this.message,
  });
  final String title;
  final String message;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text(
            title,
            style: TextStyle(fontSize: 32.0, color: Colors.black54),
          ),
          Text(
            message,
            style: TextStyle(fontSize: 16.0, color: Colors.black54),
          ),
        ],
      ),
    );
  }
}
複製代碼

若是這個 widget 的構建函數是 const 類型,它就能夠被這樣構建:

const PlaceholderContent(
  title: 'Nothing here',
  message: 'Add a new item to get started',
)
複製代碼

結果就是,這個 widget 能夠被 Flutter 優化爲,當它的父級變化時,widget 自己不會重複構建

小結:

3. 命名參數和位置參數

在 Dart 中,咱們將變量使用大括號({})包起來,由此能夠定義命名參數:

class PlaceholderContent extends StatelessWidget {
  // 使用命名參數的構建函數
  const PlaceholderContent({
    this.title,
    this.message,
  });
  final String title;
  final String message;
  
  // TODO:實現構建方法
}
複製代碼

這段代碼意味着,咱們能夠像這樣建立 widget:

PlaceholderContent(
  title: 'Nothing here',
  message: 'Add a new item to get started',
)
複製代碼

還有一種替代方案是,咱們能夠在構建函數中將大括號省略,聲明位置參數:

// 使用位置參數的構建函數
const PlaceholderContent(
  this.title,
  this.message,
);
複製代碼

結果就是,參數能夠經過它們所在的位置來定義:

PlaceholderContent(
  'Nothing here', // title 參數位於 0 號位
  'Add a new item to get started', // message 參數位於 1 號位
)
複製代碼

這徹底行得通,可是當咱們有多個參數的時候,這樣很容易引發混亂。

此時命名參數就展露優點了,它們讓代碼更易寫也更易讀。

順便說一句,你還能夠將位置參數和命名參數結合起來:

// 位置參數優先,而後是命名參數
void _showAlert(BuildContext context, {String title, String content}) {
  // TODO:展現提示信息
}
複製代碼

Flutter widget 中隨處可見使用一個位置參數,而後使用多個命名參數的方式。Text widget 就是一個很好的例子。

我寫代碼的指導思想就是,代碼必定要保持整潔、自洽。我會依照此合理選擇命名參數和位置參數。

4. @required 和默認值

默認狀況下,命名參數能夠被省略。

省略命名參數就等於給它賦值爲 null

有時候這會致使沒法預期的後果。

在上面的例子中,咱們能夠在定義 PlaceholderContent() 時並不傳入 titlemessage 參數。

這將會致使錯誤,由於這樣的話咱們會將 null 值傳入 Text widget,但這是不容許的。

@required 是一種補救方法

咱們能夠爲任何變量添加 required 註釋:

const PlaceholderContent({
  @required this.title,
  @required this.message,
});
複製代碼

這樣當咱們忘記傳入參數的時候,編譯器將會報出警告。

此時若是咱們須要,咱們仍舊能夠明確寫出傳遞 null 值:

PlaceholderContent(
  title: null,
  message: null,
)
複製代碼

此時編譯器就不會報警告了。

若是想要避免傳入 null 值,咱們能夠增長一些斷言(assert):

const PlaceholderContent({
  @required this.title,
  @required this.message,
}) : assert(title != null && message != null);
複製代碼

這些修改讓咱們的代碼安全係數更高,由於:

  • @required 會增長編譯時檢查
  • assert 會增長運行時檢查

若是咱們爲代碼加入斷言,那麼運行時的錯誤就更容易改正,由於此時的報錯會明確指出致使錯誤的代碼位置。

非空類型

@requiredassert 讓咱們的代碼安全係數更高了,可是它們看上去有些笨重。

若是咱們能夠指定對象在編譯時不可爲空就更好了。

經過使用非空類型咱們能夠作到這一點,而它在一開始就內建在 Swift 和 Kotlin 中了。

並且非空類型如今也正計劃應用於 Dart 語言。

讓咱們祈禱它能夠快點到來吧。🤞

默認值

有時候,指定合理的默認值也頗有用。

在 Dart 中這很容易就能作到:

const PlaceholderContent({
  this.title = 'Nothing here',
  this.message = 'Add a new item to get started',
}) : assert(title != null && message != null);
複製代碼

使用這種語法,若是 titlemessage 參數被忽略了,那麼默認值就會被使用。

順便提一下,默認值也能夠應用於位置參數:

int sum([int a = 0, int b = 0]) {
  return a + b;
}
print(sum(10)); // 打印出 10
複製代碼

總結

代碼是讓機器執行的,可是也是要程序員閱讀的。

時間寶貴。乖乖的寫好代碼 😉

  • 這樣才能讓你的應用更健壯,性能也更好。
  • 同時也能幫助你和你的團隊有更好的發展。

編程愉快!

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索