Dart 方法和異常與類(lèi)


?方法、異常與類(lèi)

?方法 ?一等?方法對(duì)象

可選命名參數(shù)
可選位置參數(shù)
默認(rèn)參數(shù)值
匿匿名?方法

異常 類(lèi)

構(gòu)造函數(shù) 
命名構(gòu)造函數(shù) 
初始化列列表 
重定向構(gòu)造函數(shù) 
常量量構(gòu)造函數(shù) 
?廠(chǎng)構(gòu)造函數(shù) 
Getters 和 Setters 
可覆寫(xiě)的操作符 抽象類(lèi)
接?口 可調(diào)?用的類(lèi) 

混合mixins


方法

int add(int i,int j) {
  return i + j;
}
//也可以選擇忽略類(lèi)型(不推薦)
add( i, j) {
  return i + j;
}
//對(duì)于只有一個(gè)表達(dá)式的方法,可以選擇使用縮寫(xiě)語(yǔ)法來(lái)定義:
add(i, j) => i + j;
//在箭頭 (=>) 和分號(hào) (;) 之間只能使用一個(gè) 表達(dá)式

一等方法對(duì)象

? Dart 是一個(gè)真正的面向?qū)ο笳Z(yǔ)言,方法也是對(duì)象并且具有一種 類(lèi)型 Function。 這意味著,方法可以賦值給變量,也可以當(dāng)做其他方法的參數(shù)??梢园逊椒ó?dāng)做參數(shù)調(diào)用另外一個(gè)方法

var list = [1,2,3];
//將 print 方法 作為參數(shù)傳遞給forEach
list.forEach(print);
//可以將方法賦值給一個(gè)變量 類(lèi)型為Funcation
var p = print;
list.forEach(p);

? 在Java中如果需要能夠通知調(diào)用者或者其他地方方法執(zhí)行過(guò)程的各種情況,可能需要指定一個(gè)接口,比如View的onClickListener。而在Dart中,我們可以直接指定一個(gè)回調(diào)方法給調(diào)用的方法,由調(diào)用的方法在合適的時(shí)機(jī)執(zhí)行這個(gè)回調(diào)。

void setListener(Function listener){
    listener("Success");
}
//或者
void setListener(void listener(String result)){
    listener("Success");
}

//兩種方式,第一種調(diào)用者根本不確定 回調(diào)函數(shù)的返回值、參數(shù)是些什么
//第二中則需要寫(xiě)這么一大段 太麻煩了。

//第三種:類(lèi)型定義 將返回值為voide,參數(shù)為一個(gè)String的方法定義為一個(gè)類(lèi)型。
typedef  void Listener(String result);
void setListener(Listener listener){
  listener("Success");
}

方法可以有兩種類(lèi)型的參數(shù):必需的和可選的。 必需的參數(shù)需要在參數(shù)列表前面, 后面再定義可選參數(shù)。

可選命名參數(shù)

? 把方法的參數(shù)放到 {} 中就變成可選 命名參數(shù)

int add({int i, int j}) {
  if(i == null || j == null){
     return 0;
  }
  return i + j;
}

? 調(diào)用方法的時(shí)候,可以使用這種形式 paramName: value 來(lái)指定命名參數(shù)。例如:

//無(wú)必須參數(shù)
add()
//選擇傳遞參數(shù)
add(i:1)
//位置無(wú)關(guān)
add(i:1, j:2)
add(j:1, i:2)

可選位置參數(shù)

? 把方法的參數(shù)放到 [] 中就變成可選 位置參數(shù),傳值時(shí)按照參數(shù)位置順序傳遞

int add([int i, int j]) {
  if(i == null || j == null){
     return 0;
  }
  return i + j;
}
// 1賦值給i
add(1);
// 按照順序賦值
add(1,2);

默認(rèn)參數(shù)值

? 在定義方法的時(shí)候,可選參數(shù)可以使用 = 來(lái)定義可選參數(shù)的默認(rèn)值。

int add([int i = 1, int j = 2]) => i + j;
int add({int i = 1, int j = 2}) => i + j;

匿名方法

? 沒(méi)有名字的方法,稱(chēng)之為匿名方法,也可以稱(chēng)之為 lambda 或者 closure 閉包。匿名方法的聲明為:

([Type] param1, …) { 
  codeBlock; 
}; 

? 如:

var list = ['apples', 'oranges', 'grapes', 'bananas', 'plums'];
list.forEach((i) {
  print(list[i]);
});

異常

? 和 Java 不同的是,所有的 Dart 異常是非檢查異常。 方法不一定聲明了他們所拋出的異常, 并且不要求你捕獲任何異常。

? Dart 提供了 ExceptionError 類(lèi)型, 以及一些子類(lèi)型。你還 可以定義自己的異常類(lèi)型。但是, Dart 代碼可以 拋出任何非 null 對(duì)象為異常,不僅僅是實(shí)現(xiàn)了 Exception 或者Error 的對(duì)象。

throw new Exception('這是一個(gè)異常');
throw '這是一個(gè)異常';
throw 123;

? 與Java不同之處在于捕獲異常部分,Dart中捕獲異常同樣是使用catch語(yǔ)句,但是Dart中的catch無(wú)法指定異常類(lèi)型。需要結(jié)合on來(lái)使用,基本語(yǔ)法如下:

try {
    throw 123;
} on int catch(e){
    //使用 on 指定捕獲int類(lèi)型的異常對(duì)象       
} catch(e,s){
    //函數(shù) catch() 可以帶有一個(gè)或者兩個(gè)參數(shù), 第一個(gè)參數(shù)為拋出的異常對(duì)象, 第二個(gè)為堆棧信息 ( StackTrace 對(duì)象)
    rethrow; //使用 `rethrow` 關(guān)鍵字可以 把捕獲的異常給 重新拋出
} finally{
    
}

類(lèi)

? Dart 是一個(gè)面向?qū)ο缶幊陶Z(yǔ)言。 每個(gè)對(duì)象都是一個(gè)類(lèi)的實(shí)例,所有的類(lèi)都繼承于 Object

//每個(gè)實(shí)例變量都會(huì)自動(dòng)生成一個(gè) getter 方法(隱含的)。 非final 實(shí)例變量還會(huì)自動(dòng)生成一個(gè) setter 方法。
class Point {
  num x;
  num y;
}

構(gòu)造函數(shù)

? 由于把構(gòu)造函數(shù)參數(shù)賦值給實(shí)例變量的場(chǎng)景太常見(jiàn)了, Dart 提供了一個(gè)語(yǔ)法糖來(lái)簡(jiǎn)化這個(gè)操作:

class Point {
  num x;
  num y;

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

命名構(gòu)造函數(shù)

? Dart 并不支持構(gòu)造函數(shù)的重載,而采用了命名構(gòu)造函數(shù)為一個(gè)類(lèi)實(shí)現(xiàn)多個(gè)構(gòu)造函數(shù):

class Point {
  num x;
  num y;
  Point(this.x, this.y);
  Point(this.y);///錯(cuò)誤,不允許重載
  //命名構(gòu)造函數(shù)
  Point.y(this.y) {
    x = 0;
  }
}

//使用
var p = Point.y(0);

初始化列表

? 在構(gòu)造函數(shù)函數(shù)體執(zhí)行之前會(huì)首先執(zhí)行初始化列表,非常適合用來(lái)設(shè)置 final 變量的值。

class Point {
  num x;
  num y;
  Point(this.x, this.y);
  //命名構(gòu)造函數(shù)
  Point.y(this.y) {
    x = 0;
  }

  Point.fromMap(Map map)
      : x = map['x'], // : 和c++一樣,初始化列表
        y = map['y'];
  
  Point.x(int i)
      : x = i, 
        y = 0;
}

重定向構(gòu)造函數(shù)

? 有時(shí)候一個(gè)構(gòu)造函數(shù)會(huì)調(diào)動(dòng)類(lèi)中的其他構(gòu)造函數(shù)(在Java中就是 this(...))。 一個(gè)重定向構(gòu)造函數(shù)是沒(méi)有代碼的,在構(gòu)造函數(shù)聲明后,使用 冒號(hào)調(diào)用其他構(gòu)造函數(shù)。

class Point {
  num x;
  num y;

  Point(this.x, this.y);
  Point.xy(int x,int y):this(x,y); ///調(diào)用上面的構(gòu)造函數(shù)
}

常量構(gòu)造函數(shù)

? 如果你的類(lèi)提供一個(gè)狀態(tài)不變的對(duì)象,你可以把這些對(duì)象 定義為編譯時(shí)常量。要實(shí)現(xiàn)這個(gè)功能,需要定義一個(gè) const 構(gòu)造函數(shù), 并且聲明所有類(lèi)的變量為 final。

class ImmutablePoint {
  final num x;
  final num y;
  //常量構(gòu)造函數(shù)
  const ImmutablePoint(this.x, this.y);
}

void main(){
    //編譯器常量
    var p1 = const ImmutablePoint(0,0);
    var p2 = const ImmutablePoint(0,0);
    print(p1 == p2); // true
}

工廠(chǎng)構(gòu)造函數(shù)

? 當(dāng)實(shí)現(xiàn)一個(gè)使用factory 關(guān)鍵詞修飾的構(gòu)造函數(shù)時(shí),這個(gè)構(gòu)造函數(shù)不必創(chuàng)建類(lèi)的新實(shí)例。例如,一個(gè)工廠(chǎng)構(gòu)造函數(shù) 可能從緩存中獲取一個(gè)實(shí)例并返回,或者 返回一個(gè)子類(lèi)型的實(shí)例。(工廠(chǎng)構(gòu)造函數(shù)無(wú)法訪(fǎng)問(wèn) this

class Logger {
  final String name;
  //從緩存獲取對(duì)象
  static final Map _cache = {};
  //工廠(chǎng)構(gòu)造函數(shù),無(wú)法使用this變量
  factory Logger(String name) {
    if (_cache.containsKey(name)) {
      //工廠(chǎng)構(gòu)造函數(shù)需要返回 Logger 實(shí)例對(duì)象
      return _cache[name];
    } else {
      final logger = Logger._internal(name);
      _cache[name] = logger;
      return logger;
    }
  }
  //以 _ 開(kāi)頭的函數(shù)、變量無(wú)法在庫(kù)外使用
  Logger._internal(this.name);
}

? 借助工廠(chǎng)構(gòu)造函數(shù)能夠?qū)崿F(xiàn)單例:

//使用工廠(chǎng)構(gòu)造實(shí)現(xiàn)單例
class Manager {
  static Manager _instance;
  //和static是一樣的, 區(qū)別是factory畢竟是構(gòu)造函數(shù),需要返回一個(gè)實(shí)例,而static是靜態(tài)方法。
  factory Manager.getInstance() {
    if (_instance == null) {
      _instance =  new Manager._internal();
    }
    return _instance;
  }

//  static Manager getInstance() {
//    if (_instance == null) {
//      _instance = new Manager._internal();
//    }
//    return _instance;
//  }
  Manager._internal();
}

Getters 和 Setters

? Dart中每個(gè)實(shí)例變量都隱含的具有一個(gè) getter, 如果變量不是 final 的則還有一個(gè) setter??梢酝ㄟ^(guò)實(shí)現(xiàn) getter 和 setter 來(lái)創(chuàng)建新的屬性, 使用 getset 關(guān)鍵字定義 getter 和 setter:

class Rect {
  num left;
  num top;
  num width;
  num height;

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

  //使用 get定義了一個(gè) right 屬性
  num get right             => left + width;
  set right(num value)  => left = value - width;
}

void main() {
  var rect = Rect(0, 0, 10, 10);
  print(rect.right); //10
  rect.right = 15;
  print(rect.left);  //5
}

需要注意的是,在get與set中使用自身會(huì)導(dǎo)致Stack Overflow

可覆寫(xiě)的操作符

? 把已經(jīng)定義的、有一定功能的操作符進(jìn)行重新定義??梢灾匦露x的操作符有:

| < | + | | | [] |
| ---- | ---- | ---- | ----- |
| > | / | ^ | []= |
| <= | ~/ | & | ~ |
| >= | * | << | == |
| | % | >> | |

? 比如:List就重寫(xiě)了 []

class Point {
  int x;
  int y;
  //返回值 參數(shù)隨你定義
  Point operator +(Point point) {
    return Point(x + point.x, y + point.y);
  }

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

var p1 = Point(1, 1);
var p2 = p1 + Point(2, 2);
print(p2.x); ///3
print(p2.y); ///3

抽象類(lèi)

? 使用 abstract 修飾符定義一個(gè)抽象類(lèi)。抽象類(lèi)中允許出現(xiàn)無(wú)方法體的方法

abstract class Parent {
  String name;
  void printName(); //抽象方法,不需要在方法前聲明 abstract
}

? 抽象類(lèi)不能被實(shí)例化,除非定義工廠(chǎng)方法并返回子類(lèi)。

abstract class Parent {
  String name;
  //默認(rèn)構(gòu)造方法
  Parent(this.name);
  //工廠(chǎng)方法返回Child實(shí)例
  factory Parent.test(String name){
    return new Child(name);
  }
  void printName();
}
// extends 繼承抽象類(lèi)
class Child extends Parent{
  Child(String name) : super(name);

  @override
  void printName() {
    print(name);
  }
}

void main() {
  var p = Parent.test("Lance");
  print(p.runtimeType); //輸出實(shí)際類(lèi)型 Child
  p.printName();        
}

接口

? 與Java不同,Dart中沒(méi)有interface關(guān)鍵字,Dart中每個(gè)類(lèi)都隱式的定義了一個(gè)包含所有實(shí)例成員的接口, 并且這個(gè)類(lèi)實(shí)現(xiàn)了這個(gè)接口。如果你想 創(chuàng)建類(lèi) A 來(lái)支持 類(lèi) B 的 方法,而不想繼承 B 的實(shí)現(xiàn), 則類(lèi) A 應(yīng)該實(shí)現(xiàn) B 的接口。

class Listener{
  void onComplete(){}
  void onFailure(){}
}

class MyListsner implements Listener{
  MyListsner(){

  }
  @override
  void onComplete() {
  }

  @override
  void onFailure() {
  }
}

與繼承的區(qū)別在于:

1、單繼承,多實(shí)現(xiàn)。

2、繼承可以有選擇的重寫(xiě)父類(lèi)方法并且可以使用super,實(shí)現(xiàn)強(qiáng)制重新定義接口所有成員。

可調(diào)用的類(lèi)

? 如果 Dart 類(lèi)實(shí)現(xiàn)了 call() 函數(shù)則 可以當(dāng)做方法來(lái)調(diào)用。

class Closure {
  call(String a, String b) => '$a $b!';
}

main() {
  var c = new Closure();
  var out = c("Hello","Dart");
  print(out);
}

混合mixins

? Mixins 是一種在多類(lèi)繼承中重用 一個(gè)類(lèi)代碼的方法。它的基本形式如下:

//被mixin(混入)的類(lèi)不能有構(gòu)造函數(shù)
class A  {
  void a(){}
}
class B{
  void b(){}
}
class C with A,B{
  void c(){}
}

with后面跟著需要混入的類(lèi),被mixin(混入)的類(lèi)不能有構(gòu)造函數(shù)?,F(xiàn)在的 C擁有了三個(gè)方法(a、b與c)。假設(shè)A與B 存在相同的方法,以最右側(cè)的混入類(lèi)為主,比如:

class A {
  String getMessage() => 'A';
}

class B {
  String getMessage() => 'B';
}
//
class AB with A, B {}

class BA  with B, A {}

void printMessage(obj) => print(obj.getMessage());

void main() {
  printMessage(AB()); //輸出 B
  printMessage(BA()); //輸出 A
}

繼承與mixins是兼容的

class A {
  String getMessage() => 'A';
}

class B {
  String getMessage() => 'B';
}
class P{
  String getMessage() => 'P';
}
class AB extends P with A, B {}

class BA extends P with B, A {}
//可以簡(jiǎn)寫(xiě)成:
//class AB = P with A, B;
//class BA = P with B, A;
void printMessage(obj) => print(obj.getMessage());

void main() {
  printMessage(AB()); //輸出 B
  printMessage(BA()); //輸出 A
}

? mixins彌補(bǔ)了接口和繼承的不足,繼承只能單繼承,而接口無(wú)法復(fù)用實(shí)現(xiàn),mixins卻可以多混入并且能利用到混入類(lèi)的具體實(shí)現(xiàn):

abstract class Swimming{
    void swimming(){
        print("游泳");
    }
}

abstract class Jump{
    void jump(){
        print("跳躍");
    }
}

//只能單繼承,如果需要Jump,只能以implements的形式
class Lance extends Swimming implements Jump{
    //實(shí)現(xiàn)接口
    void jump(){
        print("跳躍");
    }
}

//但是實(shí)際上,我們經(jīng)常不需要重新實(shí)現(xiàn)Jump方法,復(fù)用Jump所實(shí)現(xiàn)的jump方法就可以了
//這時(shí)使用混合能夠更加方便
class Lance1 with Swimming, Jump {}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

友情鏈接更多精彩內(nèi)容