位元詩人 從避坑開始的 Dart 入門教學

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

前言

Dart 不是學院語言 (C、C++),也不是商業語言 (Java、C#)。所以我們採取「避坑」的角度介紹這個語言,降低從其他語言轉過來時的摩擦。

當前定位

目前 Dart 最主要的用途是寫 Flutter 應用程式。這是一個跨平台 Mobile Framework。由於 Flutter 的 UI 是直接繪製的,反而不會有平台間不一致的問題。只有在深入一部分硬體底層功能時,才會撞到 Flutter 的邊界。

如果要把 Dart 當成通用語言的話,語法成熟度是足夠的。但 Dart 的 ecosystem 比較小,要懂得如何和沒有 binding 的外部庫合作。一些常見的模式是 FFI、Microservice、CLI,可根據情境來選擇。

沒有全域函式庫

主流程式語言,像 Python,會先從一個 app.py 開始,慢慢擴大 code base。必要時用 pip install 安裝全域庫來用。Python 也有基於 project 的隔離環境,但那是後來加上去的,不是原生功能。

但 Dart 一開始就沒有全域庫。使用 app.dart 單檔撰碼的話,只能用 Dart 內建庫,很快就會碰到邊界。所以,Dart 一定是基於 project 來撰碼。關鍵在於專案根目錄的那份 pubspec.yaml 設定檔。

選擇合適的 Dart 專案

這裡的「專案」不是什麼商業產品,也不是開源專案,只是用目錄和設定檔管理 Dart 程式碼的一種方式。

當你執行 dart create 時,可選的專案如下:

  • console:簡單的命令列程式,最適合初學者練習。
  • cli:帶有命令列解析的命令列程式
  • package:當你想把程式碼打包成函式庫供人使用時選擇。
  • server-shelf:用 Shelf 撰寫網頁中介程式。
  • web:用 Dart 標準函式庫寫網頁程式。

初學的話,建議用 console 專案。等到寫熟了,可以開始用 package 寫函式庫。其他專案較少使用,知道有這些選項即可。

寫一陣子後,預設專案會不夠用,這時候要學習如何手動修改 pubspec.yaml。如果有自己用得順手的專案架構,也可以弄成一個 GitHub Template Repo,以後根據這個 Repo 改就好,不用每次從頭刻。

安裝函式庫

Dart 有兩種安裝模式:

  • 局部安裝dart pub add,用來安裝專案所需的函式庫,會記錄在 pubspec.yaml
  • 全域安裝dart pub global activate,用來安裝命令列工具。

即使你全域安裝了某個工具,Dart 在執行專案代碼時,只會認定專案內的局部函式庫。這是為了保護專案穩定度,避免不同專案因為同一個函式庫的版本衝突而炸掉。

自動排版程式碼

不要花時間排 Dart 程式碼,寫完後用 dart format 自動重排。只要注意維持一致的撰碼風格,像是 camelCasePascalCasesnake_case 的差別。

這裡有個排版秘訣:多用「尾隨逗號」 (Trailing Commas)。在函式或建構式的最後一個參數後面加上逗號,dart format 就會自動幫你把長參數展開成多行,這在寫 Flutter UI 時特別有用。建議到官網看一下撰碼風格指南

自動檢查程式碼

Dart 沒必要像 Rust 那麼嚴格,連所有權、多執行緒規範都寫進編譯器。但 Dart 也不是直接放任程式碼在 runtime 炸掉的語言。

不要輕易地用 dynamic 型態或語法技巧來迴避 Dart 的 Linter 檢查。想一下為什麼會報錯,當下多花 15 分鐘弄清楚程式碼在做什麼,可以讓你晚上睡得更安穩。

Null Safety (空安全)

Dart 3.0 以後已經全面進入「100% Sound Null Safety」時代。這意味著你無法再寫出非空安全的代碼。

雖然 Dart 無法保證外部資料(如 API 回傳值)不為空,但它強制你處理。有可能為空的變數必須寫成 String? 而不是 String。善用 ?. (選用串連) 或 ?? (預設值),可以讓程式碼更簡潔,避免 null 在 runtime 導致崩潰。

主函式

Dart 的主函式很彈性。傳統的主函式如下:

void main(List<String> arguments) {
  /* 撰寫程式碼 */
}

如果你需要處理非同步(例如呼叫 API、讀寫檔案),則使用非同步模式:

Future<void> main(List<String> arguments) async {
  /* 使用 await 處理非同步邏輯 */
}

除非你的程式完全不涉及 Web 環境或非同步資源,否則習慣寫非同步模式是比較保險的做法。

道地的 Dart 程式碼

幾乎沒有人把 Dart 當成第一個語言。剛開始寫時,往往會寫出帶著其他語言味道的 Dart 程式碼。

這是正常現象。程式的底線是「能正常運作」,再來是「有效率」。寫久了,自然會發現 Dart 獨有的語法糖(如級連操作符 .. 或展開操作符 ...)能大幅縮減代碼。不用急著一次到位,別讓語法規則限制了你的解題邏輯。

結語

本文提出了一些學習 Dart 常見的坑,希望可以幫助讀者順利啟航,避開不必要的挫折。

關於作者

位元詩人 (ByteBard) 是資訊領域碩士,喜歡用開源技術來解決各式各樣的問題。這類技術跨平台、重用性高、技術生命長。

除了開源技術以外,位元詩人喜歡日本料理和黑咖啡,會一些日文,有時會自助旅行。