Dart的基礎語法

LinXunFeng發表於2021-08-07

歡迎關注微信公眾號:FSA全棧行動 ?

相關程式碼存放於:github.com/LinXunFeng/…

一、變數/常量

明確宣告

// 明確宣告
String name = 'lxf';
int age = 18;
double height = 1.8;
print('$name, $age, $height'); // lxf, 18, 1.8
複製程式碼

型別推導

var

runtimeType : 用於獲取變數當前的型別

var count = 1; // count的型別為int
print(count.runtimeType); // int
// count = "abc"; // 報錯,無法為int型別賦值一個字串
複製程式碼

dynamic

dynamic 宣告的變數可以賦值為任意型別

在開發中一般不這種做,因為會帶來潛在的危險

dynamic type = 'lxf';
print(type.runtimeType); // String

type = 18;
print(type.runtimeType); // int

// type.abc(); // 編譯期不會報錯,執行時找不到方法報錯
複製程式碼

final & const

finalconst 都用來定義變數

final gender = 'male';
// gender = 'female' // 報錯
const country = 'China';
// country = 'USA'; // 報錯
複製程式碼

區別:

  • const : 必須賦值,接收一個常量值(即編譯期間就需要確定的值)
  • final : 可以通過計算/函式動態獲取值(即執行時能確定的值)
String getName() {
  return 'lxf';
}

main(List<String> args) {
	final myName = getName();
  // const myName = getName(); // 報錯
}
複製程式碼

二、資料型別

  • int: 整數
  • double: 浮點數

注:intdouble 表示的範圍不是固定的,具體取決於執行 Dart 的平臺

整型

// 整型
int age = 18;
int hexAge = 0x12;
print(age); // 18
print(hexAge); // 18
複製程式碼

浮點型

// 浮點型別 double
double height = 1.8;
print(height); // 1.8
複製程式碼

布林型別

var isFlag = true;
print('$isFlag ${isFlag.runtimeType}'); // true bool
複製程式碼
  • Dart中沒有非0即真或非空即真
var msg = 'lxf';
if (msg) { // 報錯 Conditions must have a static type of 'bool'.
  print(msg);
}
複製程式碼

字串

// 字串
var s1 = 'hello lxf';
var s2 = "hello lxf";
複製程式碼

多行字串

// 多行字串
var s3 = '''
  hello
  hey
  lxf''';
複製程式碼

字串拼接

  • 字串和其他變數或表示式拼接: 使用 ${expression}, 如果表示式是一個識別符號, 那麼 {} 可以省略
var s4 = s1 + s2;
print(s4); // hello lxfhello lxf

var s5 = 's1 = $s1 and s4 = ${s1 + s2}';
print(s5); // s1 = hello lxf and s4 = hello lxfhello lxf
複製程式碼

三、集合

List

  • 使用 [] 字面量
var letters = ['a', 'b', 'c', 'd'];
print('$letters ${letters.runtimeType}'); // [a, b, c, d] List<String>

List<int> numbers = [1, 2, 3, 4];
print('$numbers ${numbers.runtimeType}'); // [1, 2, 3, 4] List<int>
複製程式碼

List 特有的操作

// 由於List的元素是有序的,所有它還提供了一個刪除指定索引位置上元素的方法removeAt
// List根據index刪除元素
numbers.removeAt(3);
print('$numbers'); // [2, 3, 4]
複製程式碼

Set

  • 使用 {} 字面量
  • List 的兩個不同點:Set 是無序的,且元素不重複
var lettersSet = {'a', 'b', 'c', 'd'};
print('$lettersSet ${lettersSet.runtimeType}'); // {a, b, c, d} _CompactLinkedHashSet<String>

Set<int> numbersSet = {1, 2, 3, 4};
print('$numbersSet ${numbersSet.runtimeType}'); // {1, 2, 3, 4} _CompactLinkedHashSet<int>
複製程式碼

Map

var infoMap1 = {'name': 'lxf', 'age': 18};
print('$infoMap1 ${infoMap1.runtimeType}');
// {name: lxf, age: 18} _InternalLinkedHashMap<String, Object>

Map<String, Object> infoMap2 = {'height': 1.8, 'country': 'China'};
print('$infoMap2 ${infoMap2.runtimeType}');
// {height: 1.8, country: China} _InternalLinkedHashMap<String, Object>
複製程式碼

Map 特有的操作

// 1.根據key獲取value
print(infoMap1['name']); // lxf

// 2.獲取所有的entries
print('${infoMap1.entries} ${infoMap1.entries.runtimeType}');
// (MapEntry(name: lxf), MapEntry(age: 18)) MappedIterable<String, MapEntry<String, Object>>

// 3.獲取所有的keys
print('${infoMap1.keys} ${infoMap1.keys.runtimeType}');
// (name, age) _CompactIterable<String>

// 4.獲取所有的values
print('${infoMap1.values} ${infoMap1.values.runtimeType}');
// (lxf, 18) _CompactIterable<Object>

// 5.判斷是否包含某個key或者value
print('${infoMap1.containsKey('age')} ${infoMap1.containsValue(18)}');
// true true

// 6.根據key刪除元素
infoMap1.remove('age');
print('${infoMap1}'); // {name: lxf}
複製程式碼

集合共有的操作

// 長度
print(letters.length); // 4
print(lettersSet.length); // 4
print(infoMap1.length); // 2

// 新增、刪除、包含元素
numbers.add(5);
numbersSet.add(5);
print('$numbers $numbersSet'); // [1, 2, 3, 4, 5] {1, 2, 3, 4, 5}

numbers.remove(1);
numbersSet.remove(1);
print('$numbers $numbersSet'); // [2, 3, 4, 5] {2, 3, 4, 5}

print(numbers.contains(2)); // true
print(numbersSet.contains(2)); // true
複製程式碼

四、函式

函式也是物件,型別為 Function

函式定義

注意點:Dart 不支援函式過載!(函式過載:函式名稱相同,引數不同)

返回值 函式的名稱(引數列表) {
  函式體
  return 返回值
}
複製程式碼

普通函式

num sum1(num num1, num num2) {
  return num1 + num2;
}

print(sum1(1, 2)); // 3
複製程式碼

省略了型別註釋也可以正常工作,但是不建議這麼做

sum2(num1, num2) {
  return num1 + num2;
}

print(sum2(1, 2)); // 3
複製程式碼

如果函式的實現只有一個表示式,則可以使用箭頭語法

sum3(num num1, num num2) => num1 + num2;

print(sum3(1, 2)); // 3
複製程式碼

可選引數

命名可選引數

  • 定義:命名可選引數: {param1, param2, ...}

  • 注意:

    • 如果確定傳入的引數不能為 null,則需要加 required 關鍵字
    • 如果傳入的引數可能為 null,則引數型別後面需要加 ?
// 命名可選引數
printInfo1(String name, {int? age, double? height}) {
  print('name = $name age = $age height = $height');
}

// 確定引數不能為null,需要新增 required 關鍵字
// printInfo1(String name, {required int age, required double height}) {}
複製程式碼

引數預設值

printInfo3(String name, {int age = 18, double height = 1.8}) {
  print('name = $name age = $age height = $height');
}
複製程式碼

呼叫

// 命名可選引數
printInfo1('lxf'); // name = lxf age = null height = null
printInfo1('lxf', age: 18); // name = lxf age = 18 height = null
printInfo1('lxf', age: 18, height: 1.8); // name = lxf age = 18 height = 1.8
printInfo1('lxf', height: 1.8); // name = lxf age = null height = 1.8

// 引數預設值
printInfo3('lxf'); // name = lxf age = 18 height = 1.8
複製程式碼

位置可選引數

  • 定義:位置可選引數: [param1, param2, ...]
  • 注意:位置可選引數無法使用 required 關鍵字
// 位置可選引數
printInfo2(String name, [int? age, double? height]) {
  print('name = $name age = $age height = $height');
}
複製程式碼

引數預設值

printInfo4(String name, [int age = 18, double height = 1.8]) {
  print('name = $name age = $age height = $height');
}
複製程式碼

呼叫

// 位置可選引數
printInfo2('lxf'); // name = lxf age = null height = null
printInfo2('lxf', 18); // name = lxf age = 18 height = null
printInfo2('lxf', 18, 1.8); // name = lxf age = 18 height = 1.8

// 引數預設值
printInfo4('lxf'); // name = lxf age = 18 height = 1.8
複製程式碼

五、運算子

常見的運算子

var num = 10;
print(num / 3); // 除法:3.3333333333333335
print(num ~/ 3); // 整除:3
print(num % 3); // 取模:1
複製程式碼

賦值運算子

??= : 當變數為 null 時,使用後面的內容進行賦值

// 賦值運算子
var name = null;
name ??= 'lxf';
print(name); // lxf

var name1 = 'lin';
name1 ??= 'lxf';
print(name1); // lin
複製程式碼

條件運算子

?? : 當變數為 null 時,則使用後面的值,否則使用變數的值

var temp = null;
var other = temp ?? 'lxf';
print(other); // lxf
複製程式碼

級聯

.. : 可以對物件進行連續操作

class Person {
  String name;

  Person(this.name);

  void run() {
    print("$name is running");
  }

  void eat() {
    print('$name is eating');
  }

  void swim() {
    print('$name is swimming');
  }
}

main(List<String> args) {
  final p1 = Person('lxf');
  p1.run();
  p1.eat();
  p1.swim();

  final p2 = Person('lin')
    ..run()
    ..eat()
    ..swim();
}
複製程式碼

六、流程控制

ifelse

不支援非空即真或非0即真,必須是明確的 bool 型別

var isHot = true;
if (isHot) {
  print('熱門');
} else {
  print('冷門');
}
複製程式碼

for

// for
for (var i = 0; i < 10; i++) {
  print(i);
}

// for in 遍歷集合
var names = ['lxf', 'lin'];
for (var name in names) {
  print(name);
}
複製程式碼

while

var index = 0;
while (index < 5) {
  print('index -- $index');
  index++;
}
複製程式碼

do-while

var index = 0;
do {
  print('index -- $index');
  index++;
} while (index < 10);
複製程式碼

break

  • 退出迴圈
var i = 1;
while (i <= 10) {
  if (i % 5 == 0) {
    print("滿足條件,退出迴圈");
    break;
  }
  // 繼續下一個迴圈
  i++;
}
複製程式碼

continue

  • 終止當前迭代並開始後續迭代
  • 不會退出迴圈
var num = 0;
var count = 0;

for (num = 0; num <= 20; num++) {
  if (num % 2 == 0) {
    continue;
  }
  count++;
}
print("累加次數: $count"); // 累加次數: 10
複製程式碼

switch-case

var direction = 'east';
switch (direction) {
  case 'east':
    print('東面');
    break;
  case 'south':
    print('南面');
    break;
  case 'west':
    print('西面');
    break;
  case 'north':
    print('北面');
    break;
  default:
    print('其他方向');
}
複製程式碼

六、類

類的定義如下:

class 類名 {
  型別 成員名;
  返回值型別 方法名(引數列表) {
    方法體
  }
}
複製程式碼

late 關鍵字

作用:顯式宣告一個非空的變數,但不初始化,延遲變數的初始化

預設的建構函式是無參構建函式,這意味著屬性無法從預設構建函式得到初始化,這時有兩個選擇,

選擇一:自定義一個建構函式對屬性進行初始化

選擇二:使用 late 關鍵字修飾屬性,延遲變數的初始化

加上 late 關鍵字可以通過靜態檢查,但是會帶來執行時風險,你需要保證屬性在使用前有進行初始化!

class Person {
  late String name;
  late int age;
}

main(List<String> args) {
  var p1 = Person();
  p1.name = 'lxf';
  print(p1.name); // lxf
  print(p1.age); // 報錯:LateInitializationError: Field 'age' has not been initialized.
}
複製程式碼

構造方法

普通構造方法

當類中沒有指定構造方法時,預設會有一個無參的構造方法

class Person {
  String? name;
  int? age;
}


main(List<String> args) {
  var p1 = Person(); // 預設的構造方法
}
複製程式碼

可以根據自已的需求,定義自已的構建方法,不過需要注意的是:

當定義了自已的構建方法,則預設的無參構造方法會失效,無法使用!

class Person {
  String name;
  int age;

  Person(this.name, this.age);
}
複製程式碼

命名構造方法

由於 Dart 不支援方法過載,所以沒辦法建立相同名稱的構造方法,如果希望能實現更多的構造方法,這時就需要使用命名構造方法

class Person {
  String? name;
  int? age;

  Person.withArgs(String name, int age) {
    this.name = name;
    this.age = age;
  }
}


main(List<String> args) {
  // var p1 = Person(); // 預設構造方法失效
  var p1 = Person.withArgs('lxf', 18);
  print(p1.name);
  print(p1.age);
}
複製程式碼

重定向構造方法

在一個構造方法中,呼叫另一個構造方法進行初始化

class Person {
  String name;
  int age;

  Person(this.name, this.age);

  // 重定向構造方法
  Person.from(String name): this(name, 0);
}
複製程式碼

常量構造方法

使用 const 修飾構造方法,當傳入相同引數時,可以確保建立出來的物件是相同的

注意點:

  • 擁有常量構造方法的類中,所有的成員變數必須是final修飾的
  • 為了建立出相同的物件,在使用常量構造方法時,需要使用 const 關鍵字
class Person {
  // 擁有常量構造方法的類中,所有的成員變數必須是final修飾的
  final String name;

  const Person(this.name);
}

main(List<String> args) {
  var p1 = const Person('lxf');
  var p2 = const Person('lxf');
  var p3 = const Person('lxf1');
  
  const p4 = Person4('lxf');
  
  // 判斷是不是同一個物件
  print(identical(p1, p2)); // true
  print(identical(p1, p3)); // false
  print(identical(p1, p4)); // true
}
  
複製程式碼

工廠構造方法

class Person {
  late String name;

  static final Map<String, Person> _cache = <String, Person>{};

  // 工廠構造方法
  factory Person(String name) {
    var p = _cache[name];
    if (p == null) {
      p = Person._internal(name);
      _cache[name] = p;
    }
    return p;
  }

  Person._internal(this.name);
}

main(List<String> args) {
  var p1 = Person5('lxf');
  var p2 = Person5('lxf');
  // 判斷是不是同一個物件
  print(identical(p1, p2)); // true
}
複製程式碼

注意:當工廠構造方法與預設構造方法重名時,無法被繼承,會報錯

The default constructor of superclass 'Father' (called by the implicit default constructor of 'Son') must be a generative constructor, but factory found.

父類的構造器必須是一個生成的構造器,而不能是工廠構造器
複製程式碼

如下方程式碼所示

class Father {

  factory Father() {
    return Father._internal();
  }

  Father._internal();
}

class Son extends Father {} // 編譯報錯
複製程式碼

需要新增一個生成構造器,並將工廠構造器改為命名構造器

class Father {

  Father();

  factory Father.factory() {
    return Father._internal();
  }
  Father._internal();
}

class Son extends Father {}
複製程式碼

gettersetter

當希望類中定義的屬性不輕易給外部訪問時,就可以用到 gettersetter

class Marker {
  String _color;

  String get color => _color;

  set color(String color) {
    _color = color;
  }

  Marker(this._color);
}

main(List<String> args) {
  final m = Marker('red');
  m.color = 'blue';
  print(m.color); // blue
}
複製程式碼

繼承

繼承使用 extends 關鍵字,子類中使用 super 來訪問父類

class Animal {
  String name;

  Animal(this.name);

  eat() {
    print("吃吃吃");
  }
}

class Dog extends Animal {
  Dog(String name) : super(name);
}

main(List<String> args) {
  var dog = Dog("Spike");
  dog.eat(); // 吃吃吃
  print(dog.name); // Spike
}
複製程式碼

重寫父類的方法,@override 是註釋,用來標明當前為重寫的方法,可有可無,但一般保留著

class Dog extends Animal {
  Dog(String name) : super(name);

  // 重寫父類的eat方法
  @override
  eat() {
    print("$name 在吃");
  }
}
複製程式碼

抽象類

抽象類:使用 abstract 宣告的類,用於定義通用介面,無法被例項化,方法可以沒有實現,該方法稱為抽象方法,交由子類去實現

abstract class Building {
  getHeight();

  getArea() {
    print("hello");
  }
}

class Tower extends Building {
  @override
  getHeight() {
    print("55m");
  }
}

main(List<String> args) {
  var tower = Tower();
  tower.getArea(); // hello
  tower.getHeight(); // 55m
}
複製程式碼

隱式介面

  • Dart 沒有關鍵字可以用來宣告介面,所有的類都是隱式介面

  • 當一個類被當作介面使用時,那麼實現這個介面的類必須實現介面中的所有方法

  • 實現介面使用 implements 關鍵字

  • 被實現的介面方法不可以使用 super 呼叫介面中的方法

class Runner {
  run() {
    print("running");
  }
}

abstract class Fly {
  fly();
}

class SuperPerson implements Runner, Fly {
  @override
  run() {
    // 實現介面的方法不可以呼叫super
    // 報錯:The method 'run' is always abstract in the supertype.
    // super.run();
    print('自由自在的奔跑');
  }

  @override
  fly() {
    print('起飛');
  }
}
複製程式碼

Mixin混入

Dart 不支援多繼承,使用介面時需要實現介面中的所有方法,而我們需要在當前類可以複用其它類中的實現時就需要用到 Mixin混入 的方式。

  • 定義:To implement a mixin, create a class that extends Object and declares no constructors. Unless you want your mixin to be usable as a regular class, use the mixin keyword instead of class.
  • 取自官方連結:dart.dev/guides/lang…
  • 大致意思:建立一個繼承自 Object 的類,且沒有宣告建構函式,則該類就可被混入。除非你希望你的混入類可以被當作常規類使用,否則請使用 mixin 關鍵字,而不是 class

特性:

  • mixin 關鍵字宣告混入(非必要,也可以用 class

  • 混入類繼承自 Object,且不可以有構造方法

  • on 關鍵字限定指定類的子類可以使用當前混入(不加預設限定為 Object

  • 使用 mixin 後無法被繼承

  • 使用 with 進行混入

  • 父類與混入的方法重名時,使用的是混入的方法

// mixin Runner {} // 可以不使用on,預設是 on Object

mixin Runner on Animal {
  run() {
    print('跑起來了');
  }
}

class Animal {
  run() {
    print('Animal run');
  }
}

class SuperPeople extends Animal with Runner {} // 必須繼承 Animal 才可以混入 Runner

// 報錯:'Runner' can't be mixed onto 'Object' because 'Object' doesn't implement 'Animal'.
// class Person with Runner {}

// 報錯:Classes can only extend other classes.
// class Person extends Runner {} // Runner無法被繼承

main(List<String> args) {
  var p = SuperPeople();
  p.run(); // 跑起來了(使用的是混入的方法,而不是父類中的)
}
複製程式碼

當前類、父類與混入的實現優先順序

總結:當前類 > 混入 > 父類

class A {
  void method() {
    print('I am A');
  }
}

class B {
  void method() {
    print('I am B');
  }
}

class C extends A with B {
  // void method() {
  //   print('I am C');
  // }
}

main(List<String> args) {
  var c = C();
  /**
   * C 有無自己的 method 方法實現:
   *  - 有:列印:I am C
   *  - 無:列印:I am B
   */
  c.method();
}
複製程式碼

七、列舉

// 定義列舉
enum Color { red, blue, green }

main(List<String> args) {
  print(Color.red); // Color.red

  print(Color.red.index); // 0 列舉的下標從0開始
  print(Color.blue.index); // 1

  print(Color.values); // [Color.red, Color.blue, Color.green]

  var color = Color.green;
  switch (color) {
    case Color.red:
      print("紅");
      break;
    case Color.blue:
      print("藍");
      break;
    case Color.green:
      print("綠");
      break;
  }
}
複製程式碼

八、泛型

List 使用泛型

// List
var myList = ['lxf', 18];
print(myList.runtimeType); // List<Object>

// List使用泛型,限制型別
var numList = <int>[10, 20];
List<String> nameList = ["lxf", "lin"]; // 一般使用這種

// 報錯: The element type 'int' can't be assigned to the list type 'String'.
// List<String> nameList = ["lxf", "lin", 18];
複製程式碼

Map 使用泛型

// Map
var msgMap = {1: 'one', 'name': 'lxf', 'age': 18};
print(msgMap.runtimeType); // _InternalLinkedHashMap<Object, Object>

// Map使用泛型,限制型別
var infoMap = <String, String>{'name': 'lxf', 'age': '18'};
// Map<String, String> profileMap = {'name': 'lxf', 'age': '18'}; // 一般使用這種

// 報錯:The element type 'int' can't be assigned to the map value type 'String'.
// Map<String, String> profileMap = {'name': 'lxf', 'age': 18};
複製程式碼

類定義泛型

將類的屬性以泛型做為型別宣告,由外部來決定最終的型別

class Point<T> {
  T x;
  T y;

  Point(this.x, this.y);
}

main(List<String> args) {
  Point p = Point<double>(10.5, 20.5);
  print(p.x.runtimeType); // double
}
複製程式碼

如果希望屬性的型別只能是數字,可以使用 extends 來限制泛型 T 只能為 num 的子類

class Size<T extends num> {
  T width;
  T height;

  Size(this.width, this.height);
}

main(List<String> args) {
  Size s = Size<int>(20, 10);
  // 報錯:A value of type 'Size<String>' can't be assigned to a variable of type 'Size<num>'.
  // Size s1 = Size<String>("20", "10"); 
}
複製程式碼

九、庫的使用

庫的匯入

Dart 標準庫

Dart` 標準庫的匯入字首為 `dart:
import 'dart:io';
import 'dart:html';
import 'dart:math';
複製程式碼

自定義庫

libs/math_utils.dart 檔案的內容:

num sum(num num1, num num2) {
  return num1 + num2;
}

num multiply(num num1, num num2) {
  return num1 * num2;
}
複製程式碼

使用

// 匯入自定義庫
import 'libs/math_utils.dart';

main(List<String> args) {
  print(sum(10, 20)); // 30
  print(multiply(10, 20)); // 200
}
複製程式碼

第三方庫

在專案目錄下建立 pubspec.yaml 檔案,在 dependencies 下新增需要依賴的第三方的庫名與版本

第三庫的使用說明可在 pub.flutter-io.cn 上查詢

name: dartStudy
description: this is lxf's study project
dependencies:
  dio: ^4.0.0
environment:
  sdk: ">=2.10.0 <3.0.0"
複製程式碼

填寫好依賴後,在終端下執行 dart pub get 命令,終端會自動拉取對應版本的第三方檔案,之後在程式碼中就可以匯入並使用

// 匯入第三方庫
import 'package:dio/dio.dart';

main(List<String> args) {
  getHttp();
}

void getHttp() async {
  try {
    var response = await Dio().get('http://www.google.cn');
    print(response);
  } catch (e) {
    print(e);
  }
}
複製程式碼

延遲載入

  • 作用:在需要的時候才進行載入
  • 好處:減少 App 的啟動時間
  • 使用:使用 deferred as
// 延遲載入
import 'package:dio/dio.dart' deferred as diolib;
複製程式碼

在使用延遲載入的庫中,需要呼叫 loadLibrary 以載入宣告為延遲載入的庫

main(List<String> args) async {
  // 呼叫loadLibrary方法來載入延遲載入的庫
  await diolib.loadLibrary();
  diolib.Dio().get('http://www.google.cn');
}
複製程式碼

給庫起別名

一般在與別的庫的內容衝突時使用

import 'libs/math_utils.dart' as MathUtils; // 別名

main(List<String> args) {
  print(MathUtils.sum(10, 20)); // 30
  print(MathUtils.multiply(10, 20)); // 200
}
複製程式碼

指定庫內容的顯示與隱藏

import 'libs/math_utils.dart' show sum, multiply; // show: 顯示指定的內容(即部分引入)
import 'libs/math_utils.dart' hide sum; // hide: 隱藏指定的內容
複製程式碼

librarypartpart of

作用:

  • library:定義庫名

  • part:關聯分庫檔案

  • part of:宣告隸屬哪個庫,使用的是 library 定義的庫名

特點:

  • librarypartpart of 都必須定義在檔案的第一行,否則會報錯
  • 主庫可以訪問分庫中的私有成員
  • 如果需要匯入其它庫,只能在主庫中匯入,無法在分庫中匯入,且 import 只能放在 librarypart 之間
  • 如果外部需要使用到分庫的內容,只需要匯入主庫即可

檔案目錄結構:

├── 16_庫的定義.dart
└── lib
    └── part
        ├── fitsize.dart
        ├── fitsize_part1.dart
        └── fitsize_part2.dart
複製程式碼

fitsize.dart 檔案內容

// 定義庫名
library fitsize;

// 關聯分庫
part 'fitsize_part1.dart';
part 'fitsize_part2.dart';

void fit() {
  // 可以訪問分庫下的私有成員

  part1PublicMethod(); // part1 public method
  _part1PrivateMethod(); // part1 private method

  part2PublicMethod(); // part2 public method
  _part2PrivateMethod(); // part2 private method
}
複製程式碼

fitsize_part1.dart 檔案內容

part of fitsize; // 宣告為主庫的一部分

part1PublicMethod() {
  print("part1 public method");
}

_part1PrivateMethod() {
  print("part1 private method");
}
複製程式碼

fitsize_part2.dart 檔案內容

part of fitsize; // 宣告為主庫的一部分

part2PublicMethod() {
  print("part2 public method");
}

_part2PrivateMethod() {
  print("part2 private method");
}
複製程式碼

這樣三個 dart 檔案就組成了 fitsize 庫,如果外部需要使用到分庫的內容,只需要匯入主庫即可。

如果需要匯入其它庫,只能在主庫中匯入,無法在分庫中匯入,且 import 只能放在 librarypart 之間,否則會報錯。

// fitsize.dart 主庫檔案

// 定義庫名
library fitsize;

import 'dart:io'; // 匯入其它庫,只能放在這個位置

// 關聯分庫
part 'fitsize_part1.dart';
part 'fitsize_part2.dart';
複製程式碼

export

官方不再推薦使用 part 關鍵字,而是推薦使用 export

  • 使用:在一個 dart 檔案裡使用 export 關鍵字,將其它庫檔案匯出
  • 作用:這樣外部在使用時只需要匯入一個檔案即可使用完整的庫內容

檔案目錄結構:

├── 16_庫的定義.dart
└── lib
    └── export
        ├── lxf_utils.dart
        └── source
            ├── lxf_file_util.dart
            └── lxf_math_util.dart
複製程式碼

lxf_utils.dart 檔案內容:

// 定義庫名
library lxf_utils;

// 匯出所有的庫
export './source/lxf_math_util.dart';
export './source/lxf_file_util.dart';
複製程式碼

lxf_math_util.dart 檔案內容:

num sum(num num1, num num2) {
  return num1 + num2;
}
複製程式碼

lxf_file_util.dart 檔案內容:

writeFile(String name, String dir_path) {
  print('寫入檔案 $dir_path$name ');
}
複製程式碼

匯入並呼叫

import 'lib/export/lxf_utils.dart' as utils;

main(List<String> args) {
  print(utils.sum(1, 2)); // 3
  utils.writeFile('lxf.jpg', '/lxf/Desktop/'); // 寫入檔案 /lxf/Desktop/lxf.jpg
}
複製程式碼