Flutter開始干係列-Dart2

直接開始幹,沒有爲何~html

零、註釋

首先來個很重要的註釋,代碼沒有註釋,命名又不規範,那將極度糟糕。Dart 分單行、多行、文檔註釋三種。express

  • 單行註釋
//我是單行註釋
複製代碼
  • 多行註釋
/*
多行註釋
多行註釋
多行註釋
*/
複製代碼
  • 文檔註釋 文檔註釋是由 /// 或 /** 開始的多行或單行註釋。在連續的行上使用 /// 的效果等同於多行註釋。

在一段文檔註釋中,Dart 編譯器忽略全部除括號內的文本。你可使用括號來引用類、方法、屬性、頂級變量、函數和參數。括號中的名字會在被文檔化程序元素的詞法範圍內解析。json

/// A domesticated South American camelid (Lama glama).
///
/// Andean cultures have used llamas as meat and pack
/// animals since pre-Hispanic times.
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) {
    // ...
  }
}
複製代碼

1、變量/常量

變量定義

var name = 'jk'; //定義了字符串 name 賦予初值 jk
int _age = 25; //定義了整數 age 賦予初值 25
int sex; //定義了整數 sex 默認初值 null
複製代碼

敲黑板api

  1. 定義變量可使用 var 和 具體數據類型
  2. Dart 沒有 public、private 等限定符,有 @protected 註解,帶 _ 就是私有(不管屬性 仍是函數 亦或是類),反之則不是
  3. 通常局部變量使用 var ,私有成員變量使用具體變量類型
  4. dynamic 動態類型,編譯期不執行類型檢查

常量定義

const String name = 'jk'; // 聲明字符串常量 name  賦予初值 jk
final String api = 'www.baidu.com'; 聲明字符串常量 api  賦予初值 www.baidu.com
static const port = '8080'; // 聲明字符串靜態常量 port  賦予初值 8080
複製代碼

敲黑板數組

  1. const 編譯時肯定,const 不能是實例值
  2. final 第一次運行時肯定
  3. const 在類中的話,就必須定義爲 static const

2、數據類型

number

Dart 僅有2種數字類型bash

  • int 整數值 沒有long
  • double 64位(雙精度)浮點數 沒有float
  • number 類型不能當作 string 使用,也不能直接和 string 相加,須要先toString

strings

  • String 能夠用" "或者 ' ' 來聲明,推薦使用 ' ',由於它能夠套 " ",不然須要轉義
  • ''' ''' 或 """ """ 能夠申明一個多行字符串
  • 在字符串中能夠用表達式 ${expression},也能夠用 + 號來拼接字符串

booleans

  • bool 真 -> true,假 -> false

lists(也稱爲數組arrays)

在Dart中,數組是List對象,所以它們都稱爲列表。markdown

// 如下都能定義一個列表
var list = [];
List list = List();

// 靜態常量列表
var constantList = const [1, 2, 3];
// constantList[1] = 1; // 取消註釋將會報錯

複製代碼

敲黑板dom

a. Dart 2.3 增長操做符 ... 和 ...? ,提供一種將多個元素插入 List 的簡便方法異步

//經過 ... 把 list 中全部元素 add 到 list2
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);

//若是 list 可能爲 null ,則經過 ...? 把 list 中全部元素 add 到 list2
var list;
var list2 = [0, ...?list];
assert(list2.length == 1);
複製代碼

b. Dart 2.3 還可使用 if 和 for 來構建列表async

// 使用 if 建立3個或4個元素的列表
var nav = [
 'Home',
 'Furniture',
 'Plants',
 if (promoActive) 'Outlet'
];

// 使用 for 來建立列表
var listOfInts = [1, 2, 3];
var listOfStrings = [
 '#0',
 for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');
複製代碼

sets

Dart中的 Set 存放的是一組無序的惟一的元素,在Dart2.2 Set 引入 literals

// 定了一個 Set,推斷爲 Set<String>,若是添加其餘類型將報錯
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};

// 建立空 Set
var names = <String>{}; // Set<String>
// Set<String> names = {}; // Set<String>
// var names = {}; // Map<dynamic, dynamic>
複製代碼

敲黑板

Dart 2.3 增長操做符 ... 和 ...? ,提供一種將多個元素插入 Set 的簡便方法

maps

// 如下都能定義一個圖
var maps = {
  // 鍵 值
  'a' : '123456'
};
Map maps = Map();
maps[a] = '123456';
複製代碼

敲黑板

Dart 2.3 增長操做符 ... 和 ...? ,提供一種將多個元素插入 Map 的簡便方法

Runes Symbols

感受不多用 就不看了...

3、函數

函數示例

// 聲明返回類型 bool
bool isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

// 能夠不聲明類型
isNoble(atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

// 僅有一個表達式能夠這樣寫
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
複製代碼

頂層函數 main()

每一個應用程序都必須具備頂級main()函數,該函數用做應用程序的入口點。 main()函數返回void,併爲參數提供可選的List 參數。

void main() {
  querySelector('#sample_text_id')
    ..text = 'Click me!'
    ..onClick.listen(reverseText);
}
複製代碼

敲黑板 代碼中的..語法稱爲級聯。使用級聯,能夠對單個對象的成員執行多個操做。

可選參數

函數可選參數能夠是可選命名參數,也能夠是可選位置參數,但不能2者都有

  • 可選命名參數
// 函數的時候,使用{param1, param2, ...}來聲明有命名的參數

// 定義
enableFlags({bool bold, bool hidden}) {
     // ...
}

// 調用
enableFlags(hidden : true);

// 命名參數雖然是可選的,咱們依然能夠經過 @required 註解要求必傳
const Scrollbar({Key key, @required Widget child})
複製代碼
  • 可選位置參數
// 把函數的參數放在[]以內,能夠把它們標記爲可選位置參數

// 定義
String say(String from, String msg, [String device]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  return result;
}

// 調用
say('Bob', 'Howdy', 'smoke signal');

複製代碼

敲黑板

  1. 函數不能同時擁有可選命名參數和可選位置參數
  2. 可選命名參數和可選位置參數可使用 = 設置默認值
  3. 函數能夠做爲參數傳遞,也可定義爲一個變量
  4. 函數中亦可嵌套定義函數,也可使用匿名函數
  5. 函數直接定義在文件中(頂級函數),也能夠定義在類中
  6. 全部的函數都有返回值。若是沒有定義返回值,那麼至關於隱式添加語句 return null
  7. 可選命名參數和可選位置參數,區別在於調用的時候需不須要加上參數名

4、操做符

Dart 中擁有其餘語言常見操做符

這裏說幾個不同的:

  1. Dart 中 ?? 、??= 屬於操做符,如: A ?? "a" 表示 A 爲空將返回a。A ??= "a" 表示 A 爲空,將給 A 賦值 a
  2. .. 操做符,對單個對象的成員執行多個操做
  3. ... 、...? 操做符,提供一種將多個元素插入簡便操做
  4. ?. 操做符,可空調用,避免異常

5、流程控制

可使用如下任何一種方式來控制你的Dart代碼流:

  • if 和 else (能夠用三目運算符 ?: 替代)
  • for 循環
  • while 和 do-while 循環
  • break 和 continue
  • switch 和 case
  • assert 斷言(布爾條件值爲false,使用assert語句來中斷正常執行的代碼)

7、異常

dart 使用經典的try-catch處理異常,使用關鍵字throw拋出一個異常

// 拋異常
throw new IntegerDivisionByZeroException("分母不能爲0");
// 也能夠拋出任意對象
throw 'Out of llamas!';

//處理異常
try {
      divide(10, 0);
} on IntegerDivisionByZeroException {
  // 具體類型用 on
} catch (e) {
  // 非具體類型或要使用異常對象
} finally {
    //...
}
複製代碼

8、類

Dart 是一種面嚮對象語言,包含類和基於 mixin 的繼承兩部分。每一個對象是一個類的實例,而且 Object 是全部類的父類。基於 mixin 的繼承指的是每一個類(除了 Object )都只有一個父類,類體還能夠在多個類繼承中被重用。

構造函數

若是類沒有聲明構造函數,將默認無參構造函數。子類不會繼承父類構造函數,若子類沒有聲明構造函數,將也僅默認無參構造函數

class Person {
  String name;
  int age;
  
  //默認構造方法,賦值給name和tag
  Person(this.name, this.age);

  //命名構造函數,返回一個空的Person
  Person.empty();
  
  //命名構造函數,返回設置了name的Person
  Person.forName(this.name);
  
}

// 常量構造函數 全部實例變量須要時 final 
// 常量構造函數產生的對象永遠不會改變
class ImmutablePoint {
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);

  final num x, y;

  const ImmutablePoint(this.x, this.y);
}

// 工廠構造函數
class Logger {
  final String name;
  bool mute = false;

  // _cache 是個私有的 Map,僅僅由於標註了 _
  static final Map<String, Logger> _cache =
      <String, Logger>{};

  factory Logger(String name) {
    return _cache.putIfAbsent(
        name, () => Logger._internal(name));
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}
複製代碼

調用無參構造函數順序:

  1. 初始化列表
  2. 父類無參構造函數
  3. 本類無參構造函數
class Person {
  String firstName;

  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  // Person 沒有默認無參構造函數;
  // 必須調用 super.fromJson(data).
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}
複製代碼

初始化列表

class Point {
  num x;
  num y;

  Point(this.x, this.y);

  // 初始化列表在構造函數運行前設置實例變量。
  Point.fromJson(Map jsonMap)
      : x = jsonMap['x'],
        y = jsonMap['y'] {
    print('In Point.fromJson(): ($x, $y)');
  }
}
複製代碼
  • 實例變量

全部實例變量都生成一個隱式getter方法。非 final 實例變量也會生成隱式setter方法。

class Point {
  num x; // 定義實例變量x 初始化值 null
  num y; // 定義實例變量y 初始化值 null
  num z = 0; // 定義實例變量z 初始化值 0
  
  // 自定義get set
  num get x => y + z;
  set x(num value) => x = value;
}
複製代碼

隱式接口

每一個類都隱式定義一個接口,該接口包含該類的全部實例成員及其實現的任何接口。若是要在不繼承B實現的狀況下建立支持B類API的A類,則A類應實現B接口。

// 一個 person ,包含 greet() 的隱式接口。
class Person {
  // 在這個接口中
  final _name;

  // 不在接口中,由於這是個構造函數。
  Person(this._name);

  // 在這個接口中。
  String greet(who) => 'Hello, $who. I am $_name.';
}

// Person 接口的一個實現。
class Imposter implements Person {
  // 咱們不得不定義它,但不用它。
  final _name = "";

  String greet(who) => 'Hi $who. Do you know who I am?';
}
複製代碼

覆蓋操做符

class Vector {
  final int x, y;

  Vector(this.x, this.y);

  Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
  Vector operator -(Vector v) => Vector(x - v.x, y - v.y);

}

void main() {
  final v = Vector(2, 3);
  final w = Vector(2, 2);

  assert(v + w == Vector(4, 5));
  assert(v - w == Vector(0, 1));
}
複製代碼

noSuchMethod()

這個很nice,做用是在代碼嘗試使用不存在的方法或實例變量時檢測或作出反應,您能夠覆蓋noSuchMethod()

class A {
  // 複寫這個方法,使用不存在的成員將不會收到NoSuchMethodError
  @override
  void noSuchMethod(Invocation invocation) {
    print('You tried to use a non-existent member: ' +
        '${invocation.memberName}');
  }
}
複製代碼

枚舉

在枚舉中每一個值都有一個 index getter 方法,它返回一個在枚舉聲明中從 0 開始的位置。

enum Color {
  red,
  green,
  blue
}

assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);

//要獲取枚舉中全部值的列表
List<Color> colors = Color.values;
assert(colors[2] == Color.blue);
複製代碼

Mixins

Dart 2.1中引入了對mixin關鍵字的支持,早期版本中的代碼一般使用抽象類。

Mixins是一種在多個類層次結構中重用類代碼的方法。使用mixin,則使用with關鍵字後跟一個或多個mixin名稱。

class Musician extends Performer with Musical {
  // ···
}

class Maestro extends Person with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}
複製代碼

要實現mixin,請建立一個擴展Object的類,而且不聲明構造函數。除非您但願mixin可用做常規類,不然請使用mixin關鍵字而不是class。例如:

mixin Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}
複製代碼

要指定只有某些類型可使用mixin - 例如,可使用on來指定所需的超類,使你的mixin能夠調用它沒有定義的方法:

mixin MusicalPerformer on Musician {
  // ···
}
複製代碼

9、異步支持

Futures

當你須要使用 Future 的結果時,你有兩個選擇。

  1. 使用 async 和 await
  2. 使用 Future API

使用async和await的代碼是異步的,但它看起來很像同步代碼。要使用await,代碼必須位於異步函數中,標記爲async的函數。如:

Future checkVersion() async {
  var version = await lookUpVersion();
  // Do something with version
}
複製代碼

在await表達式中,表達式的值一般是Future;若是不是,那麼該值將自動包裝在Future中。await表達式使執行暫停,直到該對象可用。

使用try,catch,最後在使用await的代碼中處理錯誤和清理:

try {
  version = await lookUpVersion();
} catch (e) {
  // React to inability to look up the version
}
複製代碼

定義異步函數,使用 async 包裹函數體

Future<String> lookUpVersion() async => '1.0.0';

Future<String> lookUpVersion() async {
    //... 
}
複製代碼

Streams

當您須要從Stream獲取值時,您有兩個選擇:

  1. 使用async和異步for循環(等待)。
  2. 使用Stream API
await for (varOrType identifier in expression) {
  // Executes each time the stream emits a value.
}
複製代碼

表達式 的值必須有Stream 類型(流類型)。執行過程以下:

  1. 在 stream 發出一個值以前等待
  2. 執行 for 循環的主體,把變量設置爲發出的值。
  3. 重複 1 和 2,直到 Stream 關閉

若是要中止監聽 stream ,你可使用 break 或者 return 語句,跳出循環並取消來自 stream 的訂閱 。

10、庫和可見性

  • 可見性

可見性經過 _ 控制,前面已經說過了

  • 使用庫

導入的惟一必需參數是指定庫的URI。

//對於內置庫
import 'dart:html';

//對於其餘庫,你可使用文件系統路徑或package:scheme
import 'dart:io';
import 'package:test/test.dart';
複製代碼
  • 指定庫前綴

若是導入兩個具備衝突標識符的庫,則能夠爲一個或兩個庫指定前綴。

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

// 使用lib1裏的元素
var element1 = Element(); 

 // 使用lib2裏的元素
var element2 = lib2.Element();    
複製代碼
  • 僅導入庫的一部分

若是隻想使用庫的一部分,則能夠有選擇地導入庫。

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

// 導入全部 除了 foo.
import 'package:lib2/lib2.dart' hide foo;
複製代碼
  • 延遲加載庫

只有dart2js支持延遲加載。Flutter,Dart VM和dartdevc不支持延遲加載。 因此不看了

相關文章
相關標籤/搜索