亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747


Dart 語言基礎(chǔ)入門篇

 

 

本文是【從零開始學(xué)習(xí),開發(fā)個(gè)Flutter App】路上的第 1 篇文章。

這篇文章介紹了 Dart 的基礎(chǔ)特性,目的在于讓大家建立對(duì) Dart 語言的總體認(rèn)知,初步掌握 Dart 的語法。

我們假定讀者已經(jīng)有一定的編程基礎(chǔ),如果你了解 JAVAScript 或者 Java 等面向?qū)ο笳Z言,那 Dart 學(xué)習(xí)起來應(yīng)該很有親切感。

Dart 是一門采取眾家之長(zhǎng)的編程語言。盡管 Dart 很多語法和 JavaScript 很相似,但 Dart 語言同時(shí)是一門強(qiáng)類型的語言,它同時(shí)結(jié)合了像 Java 這樣強(qiáng)類型面向?qū)ο笳Z言的特性,這使得它能勝任大型應(yīng)用開發(fā),同時(shí)它沒有 Java 的臃腫,Dart 語言在設(shè)計(jì)上非常簡(jiǎn)潔、靈活和高效。

JavaScript 從簡(jiǎn)單的瀏覽器腳本到服務(wù)端(nodejs),慢慢延伸到PC客戶端(electron)、App (React Native)甚至小程序開發(fā),它已然成為一門真正意義上的全棧開發(fā)語言。

如果說 JavaScript 是在漫長(zhǎng)的時(shí)光里野蠻生長(zhǎng),那 Dart 從一開始就是精心設(shè)計(jì)出來的。如果說有一門語言取代JavaScript的位置,那很可能就是Dart。

Talk is cheep,下面就讓我們來親自感受一下這門語言的吧。

變量

你可以像 JavaScript 那樣聲明一個(gè)變量:

var name = 'Bob';

編譯器會(huì)推導(dǎo)出 name 的類型是String 類型,等價(jià)于:

String name = 'Bob';

我們可以從下面代碼窺見 Dart 是強(qiáng)類型語言的特性:

var name = 'Bob';
  
// 調(diào)用 String 的方法
print(name.toLowerCase());

// 編譯錯(cuò)誤
// name = 1;

前面我們說過,Dart 除了具備簡(jiǎn)潔的特點(diǎn),而且也可以是非常靈活的,如果你想變換一個(gè)變量的類型,你也可以使用dynamic 來聲明變量,這就跟 JavaScript 一樣了:

dynamic name = 'Bob'; //String 類型
name = 1;// int 類型
print(name);

上面的代碼可以正常編譯和運(yùn)行,但除非你有足夠的理由,請(qǐng)不要輕易使用。

final 的語義和 Java 的一樣,表示該變量是不可變的:

// String 可以省略
final String name = 'Bob'; 

// 編譯錯(cuò)誤
// name = 'Mary';

其中 String 可以省略,Dart 編譯器足夠聰明地知道變量name 的類型。

如果要聲明常量,可以使用const 關(guān)鍵詞:

const PI = '3.14';

class Person{
  static const name = 'KK';
}

如果類變量,則需要聲明為static const 。

內(nèi)置類型

不像Java把類型分的特別細(xì),比如整數(shù)類型,就有byte、short、int 、long 。Dart 的類型設(shè)計(jì)相當(dāng)簡(jiǎn)潔,這也是 Dart 容易上手的原因之一,可以理解為通過犧牲空間來換取效率吧。

數(shù)值類型

Dart 內(nèi)置支持兩種數(shù)值類型,分別是int 和double ,它們的大小都是64位。

var x = 1;
// 0x開頭為16進(jìn)制整數(shù)
var hex = 0xDEADBEEF;


var y = 1.1;
// 指數(shù)形式
var exponents = 1.42e5;

需要注意的是,在Dart中,所有變量值都是一個(gè)對(duì)象,int和double類型也不例外,它們都是num類型的子類,這點(diǎn)和Java和JavaScript都不太一樣:

// String -> int
var one = int.parse('1');
assert(one == 1);

// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);

// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');

// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');

字符串

Dart 字符串使用的是UTF-16編碼。

var s = '中';
s.codeUnits.forEach((ch) => print(ch));
// 輸出為UNICODE值
20013

Dart 采用了 JavaScript 中類似模板字符串的概念,可以在字符串通過${expression}語法插入變量:

var s = "hello";
  
print('${s}, world!');
  
//可以簡(jiǎn)化成:
print('$s, world!');

//調(diào)用方法
print('${s.toUpperCase()}, world!');

Dart 可以直接通過==來比較字符串:

var s1 = "hello";
var s2 = "HELLO";
assert(s1.toUpperCase() == s2);

布爾類型

Dart 布爾類型對(duì)應(yīng)為bool關(guān)鍵詞,它有true和false兩個(gè)值,這點(diǎn)和其他語言區(qū)別不大。值得一提的是,在Dart的條件語句if和assert表達(dá)式里面,它們的值必須是bool類型,這點(diǎn)和 JavaScript 不同。

var s = '';
assert(s.isEmpty);

if(s.isNotEmpty){
// do something
}
  
//編譯錯(cuò)誤,在JavaScript常用來判斷undefined
if(s){
}

Lists

你可以把Dart中的List對(duì)應(yīng)到 JavaScript 的數(shù)組或者 Java 中的ArrayList,但 Dart 的設(shè)計(jì)更為精巧。

你可以通過類似 JavaScript 一樣聲明一個(gè)數(shù)組對(duì)象:

var list = [];
list.add('Hello');
list.add(1);

這里L(fēng)ist容器接受的類型是dynamic,你可以往里面添加任何類型的對(duì)象,但如果像這樣聲明:

var iList = [1,2,3];
iList.add(4);
//編譯錯(cuò)誤 The argument type 'String' can't be assigned to the parameter type 'int'
//iList.add('Hello');

那么Dart就會(huì)推導(dǎo)出這個(gè)List是個(gè)List<int>,從此這個(gè)List就只能接受int類型數(shù)據(jù)了,你也可以顯式聲明List的類型:

var sList = List<String>();

//在Flutter類庫中,有許多這樣的變量聲明:
List<Widget> children = const <Widget>[];

上面右邊那個(gè) const 的意思表示常量數(shù)組,在這里你可以理解為一個(gè)給children賦值了一個(gè)編譯期常量空數(shù)組,這樣的做法可以很好的節(jié)省內(nèi)存,下面的例子可以讓大家更好的理解常量數(shù)組的概念:

var constList = const <int>[1,2];
constList[0] = 2; //編譯通過, 運(yùn)行錯(cuò)誤
constList.add(3); //編譯通過, 運(yùn)行錯(cuò)誤

Dart2.3 增加了擴(kuò)展運(yùn)算符 (spread operator) ... 和...?,通過下面的例子你很容易就明白它們的用法:

var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);

如果擴(kuò)展對(duì)象可能是null,可以使用...?:

 var list;
 var list2 = [0, ...?list];
 assert(list2.length == 1);

你可以直接在元素內(nèi)進(jìn)行判斷,決定是否需要某個(gè)元素:

var promoActive = true;
var nav = [
    'Home',
    'Furniture',
    'Plants',
    promoActive? 'About':'Outlet'
];

甚至使用for來動(dòng)態(tài)添加多個(gè)元素:

var listOfInts = [1, 2, 3];
var listOfStrings = [
  '#0',
  for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');

這種動(dòng)態(tài)的能力使得 Flutter 在構(gòu)建 Widget 樹的時(shí)候非常方便。

Sets

Set的語意和其他語言的是一樣的,都是表示在容器中對(duì)象唯一。在Dart中,Set默認(rèn)是LinkedHashSet實(shí)現(xiàn),表示元素按添加先后順序排序。

聲明Set對(duì)象:

var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};

遍歷Set,遍歷除了上面提到的for...in,你還可以使用類似 Java 的 lambada 中的 forEach 形式:

halogens.add('bromine');
halogens.add('astatine');
halogens.forEach((el) => print(el));

輸出結(jié)果:

fluorine
chlorine
bromine
iodine
astatine

除了容器的對(duì)象唯一特性之外,其他基本和List是差不多的。

// 添加類型聲明:
var elements = <String>{};

var promoActive = true;
// 動(dòng)態(tài)添加元素
final navSet = {'Home', 'Furniture', promoActive? 'About':'Outlet'};

Maps

Map對(duì)象的聲明方式保持了 JavaScript 的習(xí)慣,Dart 中Map的默認(rèn)實(shí)現(xiàn)是LinkedHashMap,表示元素按添加先后順序排序。

var gifts = {
  // Key:    Value
  'first': 'partridge',
  'second': 'turtledoves',
  'fifth': 'golden rings'
};

assert(gifts['first'] == 'partridge');

添加一個(gè)鍵值對(duì):

gifts['fourth'] = 'calling birds';

遍歷Map:

gifts.forEach((key,value) => print('key: $key, value: $value'));

函數(shù)

在 Dart 中,函數(shù)本身也是個(gè)對(duì)象,它對(duì)應(yīng)的類型是Function,這意味著函數(shù)可以當(dāng)做變量的值或者作為一個(gè)方法入傳參數(shù)值。

void sayHello(var name){
  print('hello, $name');
}

void callHello(Function func, var name){
  func(name);
}

void main(){
  // 函數(shù)變量
  var helloFuc = sayHello;
  // 調(diào)用函數(shù)
  helloFuc('Girl');
  // 函數(shù)參數(shù)
  callHello(helloFuc,'Boy');
}

輸出:

hello, Girl
hello, Boy

對(duì)于只有一個(gè)表達(dá)式的簡(jiǎn)單函數(shù),你還可以通過=>讓函數(shù)變得更加簡(jiǎn)潔,=> expr在這里相當(dāng)于{ return expr; } ,我們來看一下下面的語句:

String hello(var name ) => 'hello, $name';

相當(dāng)于:

String hello(var name ){
  return 'hello, $name';
}

參數(shù)

在Flutter UI庫里面,命名參數(shù)隨處可見,下面是一個(gè)使用了命名參數(shù)(Named parameters)的例子:

void enableFlags({bool bold, bool hidden}) {...}

調(diào)用這個(gè)函數(shù):

enableFlags(bold: false);
enableFlags(hidden: false);
enableFlags(bold: true, hidden: false);

命名參數(shù)默認(rèn)是可選的,如果你需要表達(dá)該參數(shù)必傳,可以使用@required:

void enableFlags({bool bold, @required bool hidden}) {}

當(dāng)然,Dart 對(duì)于一般的函數(shù)形式也是支持的:

void enableFlags(bool bold, bool hidden) {}

和命名參數(shù)不一樣,這種形式的函數(shù)的參數(shù)默認(rèn)是都是要傳的:

enableFlags(false, true);

你可以使用[]來增加非必填參數(shù):

void enableFlags(bool bold, bool hidden, [bool option]) {}

另外,Dart 的函數(shù)還支持設(shè)置參數(shù)默認(rèn)值:

void enableFlags({bool bold = false, bool hidden = false}) {...}

String say(String from, [String device = 'carrier pigeon', String mood]) {}

匿名函數(shù)

顧名思意,匿名函數(shù)的意思就是指沒有定義函數(shù)名的函數(shù)。你應(yīng)該對(duì)此不陌生了,我們?cè)诒闅vList和Map的時(shí)候已經(jīng)使用過了,通過匿名函數(shù)可以進(jìn)一步精簡(jiǎn)代碼:

var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
  print('${list.indexOf(item)}: $item');
});

閉包

Dart支持閉包。沒有接觸過JavaScript的同學(xué)可能對(duì)閉包(closure)比較陌生,這里給大家簡(jiǎn)單解釋一下閉包。

閉包的定義比較拗口,我們不去糾結(jié)它的具體定義,而是打算通過一個(gè)具體的例子去理解它:

Function closureFunc() {
  var name = "Flutter"; // name 是一個(gè)被 init 創(chuàng)建的局部變量
  void displayName() { // displayName() 是內(nèi)部函數(shù),一個(gè)閉包
    print(name); // 使用了父函數(shù)中聲明的變量
  }
  return displayName;
}

void main(){
  //myFunc是一個(gè)displayName函數(shù)
  var myFunc = closureFunc(); //(1)
  
  // 執(zhí)行displayName函數(shù)
  myFunc(); // (2)
}

結(jié)果如我們所料的那樣打印了Flutter。

在(1)執(zhí)行完之后,name作為一個(gè)函數(shù)的局部變量,引用的對(duì)象不是應(yīng)該被回收掉了嗎?但是當(dāng)我們?cè)趦?nèi)函數(shù)調(diào)用外部的name時(shí),它依然可以神奇地被調(diào)用,這是為什么呢?

這是因?yàn)镈art在運(yùn)行內(nèi)部函數(shù)時(shí)會(huì)形成閉包,閉包是由函數(shù)以及創(chuàng)建該函數(shù)的詞法環(huán)境組合而成,這個(gè)環(huán)境包含了這個(gè)閉包創(chuàng)建時(shí)所能訪問的所有局部變量 。

我們簡(jiǎn)單變一下代碼:

Function closureFunc() {
  var name = "Flutter"; // name 是一個(gè)被 init 創(chuàng)建的局部變量
  void displayName() { // displayName() 是內(nèi)部函數(shù),一個(gè)閉包
    print(name); // 使用了父函數(shù)中聲明的變量
  }
  name = 'Dart'; //重新賦值
  return displayName;
}

結(jié)果輸出是Dart,可以看到內(nèi)部函數(shù)訪問外部函數(shù)的變量時(shí),是在同一個(gè)詞法環(huán)境中的。

返回值

在Dart中,所有的函數(shù)都必須有返回值,如果沒有的話,那將自動(dòng)返回null:

foo() {}

assert(foo() == null);

流程控制

這部分和大部分語言都一樣,在這里簡(jiǎn)單過一下就行。

if-else

if(hasHause && hasCar){
    marry();
}else if(isHandsome){
    date();
}else{
    pass();
}

循環(huán)

各種for:

var list = [1,2,3];

for(var i = 0; i != list.length; i++){}

for(var i in list){}

while和循環(huán)中斷(中斷也是在for中適用的):

  var i = 0;
  while(i != list.length){
    if(i % 2 == 0){
       continue;
    }
     print(list[i]);
  }

  i = 0;
  do{
    print(list[i]);
    if(i == 5){
      break;
    }
  }while(i != list.length);

如果對(duì)象是Iterable類型,你還可以像Java的 lambada 表達(dá)式一樣:

list.forEach((i) => print(i));
  
list.where((i) =>i % 2 == 0).forEach((i) => print(i));

switch

switch可以用于int、double、String 和enum等類型,switch 只能在同類型對(duì)象中進(jìn)行比較,進(jìn)行比較的類不要覆蓋==運(yùn)算符。

var color = '';
  switch(color){
    case "RED":
      break;
    case "BLUE":
      break;
    default:
      
  }

assert

在Dart中,assert語句經(jīng)常用來檢查參數(shù),它的完整表示是:assert(condition, optionalMessage),如果condition為false,那么將會(huì)拋出[AssertionError]異常,停止執(zhí)行程序。

assert(text != null);

assert(urlString.startsWith('https'), 'URL ($urlString) should start with "https".');

assert 通常只用于開發(fā)階段,它在產(chǎn)品運(yùn)行環(huán)境中通常會(huì)被忽略。在下面的場(chǎng)景中會(huì)打開assert:

  1. Flutter 的 debug mode。
  2. 一些開發(fā)工具比如dartdevc默認(rèn)會(huì)開啟。
  3. 一些工具,像dart 和dart2js ,可以通過參數(shù)--enable-asserts 開啟。

異常處理

Dart 的異常處理和Java很像,但是Dart中所有的異常都是非檢查型異常(unchecked exception),也就是說,你不必像 Java 一樣,被強(qiáng)制需要處理異常。

Dart 提供了Exception 和 Error 兩種類型的異常。 一般情況下,你不應(yīng)該對(duì)Error類型錯(cuò)誤進(jìn)行捕獲處理,而是盡量避免出現(xiàn)這類錯(cuò)誤。

比如OutOfMemoryError、StackOverflowError、NoSuchMethodError等都屬于Error類型錯(cuò)誤。

前面提到,因?yàn)?Dart 不像 Java 那樣可以聲明編譯期異常,這種做法可以讓代碼變得更簡(jiǎn)潔,但是容易忽略掉異常的處理,所以我們?cè)诰幋a的時(shí)候,在可能會(huì)有異常的地方要注意閱讀API文檔,另外自己寫的方法,如果有異常拋出,要在注釋處進(jìn)行聲明。比如類庫中的File類其中一個(gè)方法注釋:

  /**
   * Synchronously read the entire file contents as a list of bytes.
   *
   * Throws a [FileSystemException] if the operation fails.
   */
  Uint8List readAsBytesSync();

拋出異常

throw FormatException('Expected at least 1 section');

throw除了可以拋出異常對(duì)象,它還可以拋出任意類型對(duì)象,但建議還是使用標(biāo)準(zhǔn)的異常類作為最佳實(shí)踐。

throw 'Out of llamas!';

捕獲異常

可以通過on 關(guān)鍵詞來指定異常類型:

 var file = File("1.txt");
  try{
    file.readAsStringSync();
  } on FileSystemException {
     //do something
  }

使用catch關(guān)鍵詞獲取異常對(duì)象,catch有兩個(gè)參數(shù),第一個(gè)是異常對(duì)象,第二個(gè)是錯(cuò)誤堆棧。

try{
    file.readAsStringSync();
} on FileSystemException catch (e){
    print('exception: $e');
} catch(e, s){ //其余類型
   print('Exception details:n $e');
   print('Stack trace:n $s');
}

使用rethrow 拋給上一級(jí)處理:

 try{
    file.readAsStringSync();
  } on FileSystemException catch (e){
    print('exception: $e');
  } catch(e){
     rethrow;
  }

finally

finally一般用于釋放資源等一些操作,它表示最后一定會(huì)執(zhí)行的意思,即便try...catch中有return,它里面的代碼也會(huì)承諾執(zhí)行。

try{
     print('hello');
     return;
  } catch(e){
     rethrow;
  } finally{
     print('finally');
}

輸出:

hello
finally

Dart 是一門面向?qū)ο蟮木幊陶Z言,所有對(duì)象都是某個(gè)類的實(shí)例,所有類繼承了Object類。

一個(gè)簡(jiǎn)單的類:

class Point {
  num x, y;

  // 構(gòu)造器
  Point(this.x, this.y);
  
  // 實(shí)例方法
  num distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx * dx + dy * dy);
  }
}

類成員

Dart 通過. 來調(diào)用類成員變量和方法的。

//創(chuàng)建對(duì)象,new 關(guān)鍵字可以省略
var p = Point(2, 2);

// Set the value of the instance variable y.
p.y = 3;

// Get the value of y.
assert(p.y == 3);

// Invoke distanceTo() on p.
num distance = p.distanceTo(Point(4, 4));

你還可以通過.?來避免null對(duì)象。在Java 里面,經(jīng)常需要大量的空判斷來避免NullPonterException,這是讓人詬病Java的其中一個(gè)地方。而在Dart中,可以很方便地避免這個(gè)問題:

// If p is non-null, set its y value to 4.
p?.y = 4;

在 Dart 中,沒有private、protected、public這些關(guān)鍵詞,如果要聲明一個(gè)變量是私有的,則在變量名前添加下劃線_,聲明了私有的變量,只在本類庫中可見。

class Point{
  num _x;
  num _y;
}

構(gòu)造器(Constructor)

如果沒有聲明構(gòu)造器,Dart 會(huì)給類生成一個(gè)默認(rèn)的無參構(gòu)造器,聲明一個(gè)帶參數(shù)的構(gòu)造器,你可以像 Java這樣:

class Person{
  String name;
  int sex;
  
  Person(String name, int sex){
    this.name = name;
    this.sex = sex;
  }
}

也可以使用簡(jiǎn)化版:

Person(this.name, this.sex);

或者命名式構(gòu)造器:

Person.badGirl(){
    this.name = 'Bad Girl';
    this.sex = 1;
}

你還可以通過factory關(guān)鍵詞來創(chuàng)建實(shí)例:

Person.goodGirl(){
	this.name = 'good Girl';
	this.sex = 1;
}

factory Person(int type){
	return type == 1 ? Person.badGirl(): Person.goodGirl();
}

factory對(duì)應(yīng)到設(shè)計(jì)模式中工廠模式的語言級(jí)實(shí)現(xiàn),在 Flutter 的類庫中有大量的應(yīng)用,比如Map:

// 部分代碼
abstract class Map<K, V> {  
	factory Map.from(Map other) = LinkedHashMap<K, V>.from;
}

如果一個(gè)對(duì)象的創(chuàng)建過程比較復(fù)雜,比如需要選擇不同的子類實(shí)現(xiàn)或則需要緩存實(shí)例等,你就可以考慮通過這種方法。在上面Map例子中,通過聲明 factory來選擇了創(chuàng)建子類LinkedHashMap(LinkedHashMap.from也是一個(gè)factory,里面是具體的創(chuàng)建過程)。

如果你想在對(duì)象創(chuàng)建之前的時(shí)候還想做點(diǎn)什么,比如參數(shù)校驗(yàn),你可以通過下面的方法:

 Person(this.name, this.sex): assert(sex == 1)

在構(gòu)造器后面添加的一些簡(jiǎn)單操作叫做initializer list

在Dart中,初始化的順序如下:

  1. 執(zhí)行initializer list;
  2. 執(zhí)行父類的構(gòu)造器;
  3. 執(zhí)行子類的構(gòu)造器。
class Person{
  String name;
  int sex;

  Person(this.sex): name = 'a', assert(sex == 1){
    this.name = 'b';
    print('Person');
  }

}

class Man extends Person{
   Man(): super(1){
     this.name = 'c';
     print('Man');
   }
}

void main(){
  Person person = Man();
  print('name : ${person.name}');
}

上面的代碼輸出為:

Person
Man
name : c

如果子類構(gòu)造器沒有顯式調(diào)用父類構(gòu)造器,那么默認(rèn)會(huì)調(diào)用父類的默認(rèn)無參構(gòu)造器。顯式調(diào)用父類的構(gòu)造器:

Man(height): this.height = height, super(1);

重定向構(gòu)造器:

Man(this.height, this.age): assert(height > 0), assert(age > 0);

Man.old(): this(12, 60); //調(diào)用上面的構(gòu)造器

Getter 和 Setter

在 Dart 中,對(duì) Getter 和 Setter 方法有專門的優(yōu)化。即便沒有聲明,每個(gè)類變量也會(huì)默認(rèn)有一個(gè)get方法,在隱含接口章節(jié)會(huì)有體現(xiàn)。

class Rectangle {
  num left, top, width, height;

  Rectangle(this.left, this.top, this.width, this.height);

  num get right => left + width;
  set right(num value) => left = value - width;
  num get bottom => top + height;
  set bottom(num value) => top = value - height;
}

void main() {
  var rect = Rectangle(3, 4, 20, 15);
  assert(rect.left == 3);
  rect.right = 12;
  assert(rect.left == -8);
}

抽象類

Dart 的抽象類和Java差不多,除了不可以實(shí)例化,可以聲明抽象方法之外,和一般類沒有區(qū)別。

abstract class AbstractContainer {
  num _width;

  void updateChildren(); // 抽象方法,強(qiáng)制繼承子類實(shí)現(xiàn)該方法。

  get width => this._width;
  
  int sqrt(){
    return _width * _width;
  }
}

隱含接口

Dart 中的每個(gè)類都隱含了定義了一個(gè)接口,這個(gè)接口包含了這個(gè)類的所有成員變量和方法,你可以通過implements關(guān)鍵詞來重新實(shí)現(xiàn)相關(guān)的接口方法:

class Person {
  //隱含了 get 方法
  final _name;

  Person(this._name);

  String greet(String who) => 'Hello, $who. I am $_name.';
}

class Impostor implements Person {
  // 需要重新實(shí)現(xiàn)
  get _name => '';

  // 需要重新實(shí)現(xiàn)
  String greet(String who) => 'Hi $who. Do you know who I am?';
}

實(shí)現(xiàn)多個(gè)接口:

class Point implements Comparable, Location {...}

繼承

和Java基本一致,繼承使用extends關(guān)鍵詞:

class Television {
  void turnOn() {
    doSomthing();
  }
}

class SmartTelevision extends Television {

  @override
  void turnOn() {
    super.turnOn(); //調(diào)用父類方法
    doMore();
  }
}

重載操作符

比較特別的是,Dart 還允許重載操作符,比如List類支持的下標(biāo)訪問元素,就定義了相關(guān)的接口:

 E operator [](int index);

我們通過下面的實(shí)例來進(jìn)一步說明重載操作符:

class MyList{

  var list = [1,2,3];

  operator [](int index){
    return list[index];
  }
}

void main() {
  var list = MyList();
  print(list[1]); //輸出 2
}

擴(kuò)展方法

這個(gè)特性也是Dart讓人眼前一亮的地方(Dart2.7之后才支持),可以對(duì)標(biāo)到 JavaScript 中的 prototype。通過這個(gè)特性,你甚至可以給類庫添加新的方法:

//通過關(guān)鍵詞 extension 給 String 類添加新方法
extension NumberParsing on String {
  int parseInt() {
    return int.parse(this);
  }
}

后面String對(duì)象就可以調(diào)用該方法了:

print('42'.parseInt()); 

枚舉類型

枚舉類型和保持和Java的關(guān)鍵詞一致:

enum Color { red, green, blue }

在switch中使用:

// color 是 enmu Color 類型
switch(color){
    case Color.red:
      break;
    case Color.blue:
      break;
    case Color.green:
      break;
    default:
      break;
}

枚舉類型還有一個(gè)index的getter,它是個(gè)連續(xù)的數(shù)字序列,從0開始:

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

新特性:Mixins

這個(gè)特性進(jìn)一步增強(qiáng)了代碼復(fù)用的能力,如果你有寫過Android的布局XML代碼或者Freemaker模板的話,那這個(gè)特性就可以理解為其中inlclude 的功能。

聲明一個(gè)mixin類:

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');
    }
  }
}

通過with關(guān)鍵詞進(jìn)行復(fù)用:

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

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

mixin類甚至可以通過on關(guān)鍵詞實(shí)現(xiàn)繼承的功能:

mixin MusicalPerformer on Musician {
  // ···
}

類變量和類方法

class Queue {
  //類變量
  static int maxLength = 1000;
  // 類常量
  static const initialCapacity = 16;
  // 類方法
  static void modifyMax(int max){
    _maxLength = max;
  }
}

void main() {
  print(Queue.initialCapacity);
  Queue.modifyMax(2);
  print(Queue._maxLength);
}

泛型

在面向?qū)ο蟮恼Z言中,泛型主要的作用有兩點(diǎn):

1、類型安全檢查,把錯(cuò)誤扼殺在編譯期:

var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
//編譯錯(cuò)誤
names.add(42); 

2、增強(qiáng)代碼復(fù)用,比如下面的代碼:

abstract class ObjectCache {
  Object getByKey(String key);
  void setByKey(String key, Object value);
}

abstract class StringCache {
  String getByKey(String key);
  void setByKey(String key, String value);
}

你可以通過泛型把它們合并成一個(gè)類:

abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}

在Java中,泛型是通過類型擦除來實(shí)現(xiàn)的,但在Dart中實(shí)打?qū)嵉姆盒停?/p>

 var names = <String>[];
 names.addAll(['Tom',"Cat"]);
 // is 可以用于類型判斷
 print(names is List<String>); // true
 print(names is List); // true
 print(names is List<int>); //false

你可以通過extends關(guān)鍵詞來限制泛型類型,這點(diǎn)和Java一樣:

abstract class Animal{}
class Cat extends Animal{}
class Ext<T extends Animal>{
  T data;
}

void main() {
  var e = Ext(); // ok
  var e1 = Ext<Animal>(); // ok
  var e2 = Ext<Cat>(); // ok
  var e3 = Ext<int>(); // compile error
}

使用類庫

有生命力的編程語言,它背后都有一個(gè)強(qiáng)大的類庫,它們可以讓我們站在巨人的肩膀上,又免于重新造輪子。

導(dǎo)入類庫

在Dart里面,通過import關(guān)鍵詞來導(dǎo)入類庫。

內(nèi)置的類庫使用dart:開頭引入:

import 'dart:io';

了解更多內(nèi)置的類庫可以查看這里。

第三方類庫或者本地的dart文件用package:開頭:

比如導(dǎo)入用于網(wǎng)絡(luò)請(qǐng)求的dio庫:

import 'package:dio/dio.dart';

Dart 應(yīng)用本身就是一個(gè)庫,比如我的應(yīng)用名是ccsys,導(dǎo)入其他文件夾的類:

import 'package:ccsys/common/net_utils.dart';
import 'package:ccsys/model/user.dart';

如果你使用IDE來開發(fā),一般這個(gè)事情不用你來操心,它會(huì)自動(dòng)幫你導(dǎo)入的。

Dart 通過pub.dev來管理類庫,類似Java世界的Maven 或者Node.js的npm一樣,你可以在里面找到非常多實(shí)用的庫。

解決類名沖突

如果導(dǎo)入的類庫有類名沖突,可以通過as使用別名來避免這個(gè)問題:

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

// 使用來自 lib1 的 Element
Element element1 = Element();

// 使用來自 lib2 的 Element
lib2.Element element2 = lib2.Element();

導(dǎo)入部分類

在一個(gè)dart文件中,可能會(huì)存在很多個(gè)類,如果你只想引用其中幾個(gè),你可以增加show或者h(yuǎn)ide來處理:

//文件:my_lib.dart
class One {}

class Two{}

class Three{}

使用show導(dǎo)入One和Two類:

//文件:test.dart
import 'my_lib.dart' show One, Two;

void main() {
  var one = One();
  var two = Two();
  //compile error
  var three = Three();
}

也可以使用hide排除Three,和上面是等價(jià)的:

//文件:test.dart
import 'my_lib.dart' hide Three;

void main() {
  var one = One();
  var two = Two();
}

延遲加載庫

目前只有在web app(dart2js)中才支持延遲加載,F(xiàn)lutter、Dart VM是不支持的,我們這里僅做一下簡(jiǎn)單介紹。

你需要通過deferred as來聲明延遲加載該類庫:

import 'package:greetings/hello.dart' deferred as hello;

當(dāng)你需要使用的時(shí)候,通過loadLibrary()加載:

Future greet() async {
  await hello.loadLibrary();
  hello.printGreeting();
}

你可以多次調(diào)用loadLibrary,它不會(huì)被重復(fù)加載。

異步支持

這個(gè)話題稍微復(fù)雜,我們將用另外一篇文章獨(dú)立討論這個(gè)問題,請(qǐng)留意下一篇內(nèi)容。

參考資料

  1. 學(xué)習(xí)Dart的十大理由
  2. A tour of the Dart language
  3. Dart 常量構(gòu)造器的理解
  4. JavaScript 閉包

關(guān)于AgileStudio

我們是一支由資深獨(dú)立開發(fā)者和設(shè)計(jì)師組成的團(tuán)隊(duì),成員均有扎實(shí)的技術(shù)實(shí)力和多年的產(chǎn)品設(shè)計(jì)開發(fā)經(jīng)驗(yàn),提供可信賴的軟件定制服務(wù)。

分享到:
標(biāo)簽:語言 Dart
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定