iT邦幫忙

2024 iThome 鐵人賽

DAY 8
0
Mobile Development

Flutter基礎入門系列 第 8

【Day 08】Flutter必備技能:Dart的語法

  • 分享至 

  • xImage
  •  

在跟著手把手教學做了個簡單的應用程式後,應該會對Dart的語法有點基礎概念了吧。今天,筆者將整理一些dart基礎語法,讓未來寫flutter程式時可以更快速,少一些語法錯誤。本篇將會假設讀者已經會c語言,並省略部份與c相同內容的說明。
以下為此篇所參考的資料來源:

下載安裝Dart SDK

之前在做flutter專案時就已經在寫dart程式,且flutter的安裝並未特別要求我們需要先安裝dart sdk,各位應該都可以猜到其中的原因。沒錯,Flutter SDK中已經包含了Dart SDK,所以已經安裝了Flutter的人,可以不必再去安裝Dart了。若未下載flutter或是只想安裝dart的,這裡是官方下載說明文件。

Dart語法入門

Dart是個有點類似c語言的一種程式語言,因此在函式、變數宣告等地方都有點相似,且與c相同,每行執行的程式最後都須加上個分號;

main()

與c相同,每個程式都將會執行程式碼中的main()函數,也是一個dart程式的必要項目。若程式需要,dart中的main跟c一樣,可以加入arguments。

void main() {
  print('Hello, World!');
}

變數

命名

變數的命名規則:

  1. 多使用Camel Case命名
  2. 變數名稱的第一個字元不可是數字
  3. 不可使用特殊符號(_例外)

型態

Dart的變數有一個特別的地方,是宣告變數時不必特別指定他們的資料型態,只需要一個var,便能涵蓋所有的變數。當然,若是想要,也可以指定資料型態。
關於dynamicObject可參考此連結

var someNum = 23423;
var anotherNum = 42.58;
var someBool = true;
var someString = "asdfaklf";
String anotherString = "asdjrlkweg";

// special types, think before using
dynamic something = "Turns off type checking until runtime";
Object anotherThing = "Tells system that it is an object, but don't assume its type";

初始值

Dart在變數這方面有個功能稱為Null Safety,除非特別指定,否則變數必須設定個非null的初始值,否則會出現null dereference error
若真的要將變數設為null,則在宣告變數時,在型態後面加上個問號?,此資料型態稱為Nullable Type,但須注意的是,包含nullable type的那行程式將無法存取properties及呼叫函式。

int someNum = 0; // Non-nullable type
int? anotherNum; // Nullable type

另外,我們也可以使用late在宣告變數,這告訴dart:「我們之後必定會在使用這個變數前設定一個非null的值,但不是現在」。

late String description;

void main() {
  description = 'adsfjal';
  print(description);
}

想要避免一個變數的值在宣告後受到變動,我們可以使用final或是const來代替var,或者是放在變數型態之前。
p.s. Instance variables can be final but not const

final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';

判斷式與迴圈

包含if, else, for, while, switch, break, continue這些保留字。這部份與c語言極其相似,故不細談。
另外darts中switch並不會有fall through,因此若非一個case沒有任何執行內容,否則可省略break

if (year >= 2001) {
  print('21st century');
} else if (year >= 1901) {
  print('20th century');
}

for (final object in flybyObjects) {
  print(object);
}

for (int month = 1; month <= 12; month++) {
  print(month);
}

while (year < 2016) {
  year += 1;
}

Comments

除了常見的///*comment*/以外,dart還有另一種稱為Documentation Comments,長相為////**comment**/,多用於開發人員所用的文件說明。

/// A domesticated South American camelid (Lama glama).
///
/// Andean cultures have used llamas as meat and pack
/// animals since pre-Hispanic times.
///
/// Just like any other animal, llamas need to eat,
/// so don't forget to [feed] them some [Food].
class Llama {
  String? name;

  /// Feeds your llama [food].
  ///
  /// The typical llama eats one bale of hay per week.
  void feed(Food food) {
    // ...
  }

  /// Exercises your llama with an [activity] for
  /// [timeLimit] minutes.
  void exercise(Activity activity, int timeLimit) {
    // ...
  }
}

以上程式範例中,在class所生成的說明文檔documentation中,[feed]會成為一個連結連接到feed的函式,[Food]則會成為一個連結連接到Food這個class。

函式

宣告方式與c相同。雖然不是必要,但建議指定函式回傳值跟argument的資料型態。

int fibonacci(int n) {
  if (n == 0 || n == 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

var result = fibonacci(20);

若函式內僅有一行,可使用=> expr;代替{ return expr; },而=>又可被稱為arrow syntax
note: Only expressions can appear between the arrow (=>) and the semicolon (;). Expressions evaluate to values.

int addOne(int num) {
  return num+1;
}

int addTwo(int num) => num+2;

函式可以談的內容非常多,未避免此篇文太過冗長,更多詳細內容請見此連結

import

用於使用其他libraries的API。在dart中,每個dart檔案都是一個library。

// Importing core libraries, starts with "dart"
import 'dart:math';

// Importing libraries from external packages, starts with "package"
import 'package:test/test.dart';

// Importing files
import 'path/to/my_other_file.dart';

指定前綴

倘若有libraries的物件名稱之間有衝突(如相同名稱),可使用as來設定使用該library所用的前綴。

import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;

// Uses Element from lib1.
Element element1 = Element();

// Uses Element from lib2.
lib2.Element element2 = lib2.Element();

選擇性import

// Import only foo.
import 'package:lib1/lib1.dart' show foo;

// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;

Lazy Loading

很可能有些人不太熟悉什麼事Lazy Loading,筆者也是在接觸Neovim後才知道這個詞的。Lazy Loading(a.k.a. Deferred Loading)是僅在一個Library的物件被使用時,才會載入它,這可以加速我們最初開啟程式所需要的時間。

Dart的Lazy Loading僅支援web使用者,這點須注意。

欲lazy load一個library,我們須在import使用deferred as,而要使用該library時,則用loadLibrary()載入內容。

import 'package:greetings/hello.dart' deferred as hello;
Future<void> greet() async {
  await hello.loadLibrary();
  hello.printGreeting();
}

更多詳細說明,見此連結

Class

以下程式範例為一個包含3個properties,2個constructors,以及1個函式。其中,launchYear這個property無法從class外面存取,不能直接設定它的值,因此它是由getter method來宣告,而非變數的形式。
更多內容說明,請見此連結

class Spacecraft {
  String name;
  DateTime? launchDate;

  // Read-only non-final property
  int? get launchYear => launchDate?.year;

  // Constructor, with syntactic sugar for assignment to members.
  Spacecraft(this.name, this.launchDate) {
    // Initialization code goes here.
  }

  // Named constructor that forwards to the default one.
  Spacecraft.unlaunched(String name) : this(name, null);

  // Method.
  void describe() {
    print('Spacecraft: $name');
    // Type promotion doesn't work on getters.
    var launchDate = this.launchDate;
    if (launchDate != null) {
      int years = DateTime.now().difference(launchDate).inDays ~/ 365;
      print('Launched: $launchYear ($years years ago)');
    } else {
      print('Unlaunched');
    }
  }
}

Enumerator

最基本的enumerator長的像這樣:

enum Color { red, green, blue };

進階內容

Dart的enum可以像class有各種不同field、函示及建構式。宣告方法與class類似,但有著更多需求限制:

  • instance皆必須為final
  • generative constructor必須為const
  • factory constructor只能回傳一個固定且已知的enum instance
  • 無法被extended
  • 不可override index, hashCode, ==
  • emun內不可有物件命名為values,因已經自動生成了一個名為getter的static value
enum Vehicle implements Comparable<Vehicle> {
  car(tires: 4, passengers: 5, carbonPerKilometer: 400),
  bus(tires: 6, passengers: 50, carbonPerKilometer: 800),
  bicycle(tires: 2, passengers: 1, carbonPerKilometer: 0);

  const Vehicle({
    required this.tires,
    required this.passengers,
    required this.carbonPerKilometer,
  });

  final int tires;
  final int passengers;
  final int carbonPerKilometer;

  int get carbonFootprint => (carbonPerKilometer / passengers).round();

  bool get isTwoWheeled => this == Vehicle.bicycle;

  @override
  int compareTo(Vehicle other) => carbonFootprint - other.carbonFootprint;
}

async

asyncawait可增加程式的閱讀性,並避免*Callback Hell*。
更多詳細說明見此連結

const oneSecond = Duration(seconds: 1);

// the following methods are equivalent
Future<void> printWithDelay(String message) async {
  await Future.delayed(oneSecond);
  print(message);
}

Future<void> printWithDelay(String message) {
  return Future.delayed(oneSecond).then((_) {
    print(message);
  });
}

Error Handling

與c相似,使用try, on, catch, finally, throw,亦有著rethrow讓caller可看到exception。
更多範例見此連結

if (astronauts == 0) => throw StateError('No astronauts.');

Future<void> describeFlybyObjects(List<String> flybyObjects) async {
  try {
    for (final object in flybyObjects) {
      var description = await File('$object.txt').readAsString();
      print(description);
    }
  } on IOException catch (e) { // can have multiple on
    print('Could not describe object: $e');
  } finally {
    flybyObjects.clear();
  }
}

assert

在開發過程中,我們可以使用assert(<condition>, <optionalMessage>);來debug,若condition的布林值是false,會中斷程式的運行。

Darts語法的重點內容

  1. 所有可以放入變數的東西都是object,所有object都是class的instance
  2. 可選擇性指定資料型態(利用var
  3. 預設為開啟null safety,變數不可設定為null除非宣告時在變數型態後加上?
  4. 想特別指示變數可以是任何型態,使用Object;關閉型態驗證直到程式執行時,使用dymamic
  5. 支援generic types,如List<int> List<Object>
  6. 若一個identifier的命名中第一個字元為_,則該物件是library中的private內容,詳見此連結
  7. 命名中第一個字元為字母或是底線_,後續字元為數字、字母、底線的混合。
  8. Dart工具可回報兩種程式碼問題:warnings(程式可能有問題,但可以執行)與errors(程式有問題且不能執行)。Errors又分為compile-time(無法執行)跟run-time(當執行時exception被提出)。

謝謝閱讀到這裡的讀者,有任何問題或是想說的,都歡迎留言及email~

最後是一些小心得:
我自認為,寫了這麼多,有點像是在複習C語言,實作時自己肯定又會回去看那些說明文件。不過其實心理很高興官方文件寫的這麼簡單明瞭,在查找與學習上非常方便,尤其是入門教學文章末尾的重點整理,那真的幫我一下子複習完剛剛讀到的所有內容。


上一篇
【Day 07】製作一個app - 滾動列表與剪貼簿
下一篇
【Day 09】設計的第一步驟:介面規劃與功能設定
系列文
Flutter基礎入門30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言