第八節: Dart中泛型/泛型定義與使用

Dart 語法學習目錄

第一節: Dart 語法了解,認識變量,常量,數據類型
第二節: Dart 操作符(運算符)
第三節: Dart 中流程控制,條件判斷以及循環語句
第四節: Dart 中常用集合 List/Map
第五節: Dart 函數使用,聲明函數/匿名函數/可選參數/作用域/閉包
第六節: Dart 面向對象/構造函數/靜態屬性
第七節: Dart中抽象類abstract/接口implements/混入Mixin
第八節: Dart中泛型/泛型定義與使用
第九節: Dart 中的庫/自定義庫/內置庫/第三方庫


1. Dart 泛型

1.1 泛型的理解

在 API 文檔中你會發現基礎數組類型 List 的實際類型是 List<E> 。 <…> 符號將 List 標記為 泛型 (或 參數化) 類型。 這種類型具有形式化的參數。 通常情況下,使用一個字母來代表類型參數, 例如 E, T, S, K, 和 V 等。

泛型:通俗的理解: 就是解決類的接口, 方法, 復用性, 以及對不特定數據類型的支持(類型校驗),

在通俗一點,就是對于類型的約束.


1.2 泛型的定義
  1. 使用 <…> 來聲明泛型
  2. 通常情況下,使用一個字母來代表類型參數, 例如 E, T, S, K, 和 V 等。
  3. List 定義的泛型*(或者 參數化) 類型,定義為List<E>


1.3 使用泛型的原因
  1. 在 Dart 中類型是可選的,可以通過泛型來限定類型。
  2. 使用泛型可以有效地減少重復的代碼。
  3. 泛型可以在多種類型之間定義同一個實現,同時還可以繼續使用檢查模式和靜態分析工具提供的代碼分析功能。
  4. 如果你需要更加安全的類型檢查,則可以使用 參數化定義。


1.4 泛型的好處

泛型的好處不僅僅是保證代碼的正常運行:

  1. 正確指定泛型類型可以提高代碼質量。
  2. 使用泛型可以減少重復的代碼。


接下來看看泛型的使用


2. 泛型的使用

在使用泛型之前,我們先看看一些需求,來理解泛型

需求: 有一個類, 輸入什么類型返回什么類型


2.1 需求示例理解泛型的使用場景

那么我們可能會如下的寫法

void main(){
    int getInfo(int value){
        return value;
    }

    var num = getInfo(123);
    print(num);
} 

這樣的寫法只能滿足我們在傳入數字類型,返回數字類型,如果傳入字符串類型就會報錯,

這樣的局限性就會很大,如果你還想開發一個傳入字符串類型,返回字符串類型的函數,你就需要在一個函數.這樣代碼量就會變的很大,那么怎樣才能讓一個方法復用呢,減少代碼量


那么有些人可能就會在想,我們可以把類型限制去掉

如下

void main(){
    getInfo(value){
        return value;
    }

    var num = getInfo(123);
    print(num);
} 

這樣雖然可以實現最開始的學需求,但是這么寫毫無意義. 在真實開發中,隨時有可能你傳入的值和返回的值類型不同

void main(){
    getInfo(value){
        value = '' + value;
        return value;
    }

    var num = getInfo(123);
    print(num);
} 

如示例,這樣不會報錯,同時也不會有類型檢查


所以我們就可以使用泛型,泛型簡而言之,就是我不知道用戶輸入什么類型的值, 用一個標記符號代替,這個標記符號就是這種類型,在所有需要同一類型的地方使用這種標記,

那么這個標記到底代表什么類型,等到被調用的時候由用戶來制定.

例如:


void main(){
    T getInfo<T>(T value){
        return value;
    }

    // 制定getInfo 參數和返回都是int類型
    var num = getInfo<int>(123);
    print(num);           // 123
    print(num is int);    // true

    // 指定getInfo 參數和返回都是String類型
    var str = getInfo<String>("hello");
    print(str);             // hello
    print(str is String);   // true

} 

通過例子我們就會了解,函數的參數的類型和返回的類型不是有定義函數是決定的,而是用了一個字母T代表類型,這個類型在調用這個方法的時候才會決定.


當然了,可能會有人問,那么我在調用的時候可不可以不指定類型, 完全沒有問題,

如下調用依然可以

var num = getInfo(123);
print(num);           // 123
print(num is int);    // true

此時你就可以傳入任何類型

其實dart有很多內置的方法都是用了泛型,我們可以通過下面了解


2.2 了解dart內置方法的泛型

dart中很多類都定義了泛型,就以List為例來看看dart中內置的泛型

void main(){
    // 未指定類型的List
    List list = List();
    list.add("蘋果");
    list.add(123);
    print(list);  // [蘋果, 123]

    // 限定List 泛型為String
    List list2 = List<String>();
    list2.add("李子");
    list2.add(333);
    print(list2);  //報錯: type 'int' is not a subtype of type 'String' of 'value'
}

這個時候機會發現, List中的類型不是在定義時決定的,而是在使用時決定的,如果在使用List時沒有指定類型,那么list中可以添加任何類型的內容, 如果指定了特定的類型,這個集合中將只能傳入指定類型的數據,否則就報錯,類型不對.

那么接下來就看看泛型的使用


2.3 泛型函數

最初,Dart 的泛型只能用于類。 新語法的泛型,允許在方法和函數上使用類型參數:

其實上面的示例中我們已經用到了泛型函數,

示例:

T getInfo<T> (T value){
    T num = value;
    return num;
}

示例函數中不同的T各表示什么意思

T(表示getInfo返回值的類型) getInfo<T>這個T就是接受使用getInfo時指定的類型 (T (參數類型) value) {

? T 定義變量時的類型 num =value;

}

所有T表示的類型都是一樣的, 由使用函數的時候指定的類型.


函數使用泛型地方說明

  1. 函數的返回值類型 (T)。
  2. 參數的類型 (T value).
  3. 局部變量的類型 (T num).

至于函數名后面的<T>,負責接受來確定T代表哪一種類型.


2.4 類泛型

dart中可以在定義類是使用泛型.

在類名字后面使用尖括號(<...>)來指定 泛型類型。

class Person<T>{

    T sayhello(T value){
        print("hello,我是$value");
        return value;
    }
}

void main(){
    Person student = new Person<String>();
    var name = student.sayhello("小明");      // hello,我是小明
    print(name);                             // 小明
    print(name is String);                   // true
}

在定義類時使用泛型, 類中的方法,包括屬性都可以使用泛型


3. 限制泛型類型

說明:

當需要對泛型的具體類型進行限定的時候,可以使用extends 關鍵字來限定泛型參數的具體類型。


3.1 不限制泛型類型的時候

也就是說我們制定定義的泛型是完全由使用這決定的

例如

class Person<T>{

    T sayhello(T value){
        print("hello,我是$value");
        return value;
    }
}

void main(){
    Person student = new Person<String>();
    var name = student.sayhello("小明");  // hello,我是小明
    print(name);       // 小明
    print(name is String);    // true


    Person student2 = new Person<int>();
    var name2 = student2.sayhello(123);  // hello,我是123
    print(name2);           // 123
    print(name2 is int);    // true
}

Person中T所代表的類型完全是使用時指定什么類型就是什么類型,

但是有的時候就需要對泛型進行限制.


3.2 限制泛型的類型

在需要的使用通過extends類限定泛型的類型

將上例中的泛型加以限制.

示例:

class Person<T extends String>{

    T sayhello(T value){
        print("hello,我是$value");
        return value;
    }
}

一旦你更改后在此運行,你會發現報錯, 因為此時使用這個類型,泛型只能是字符串類型, 你傳入的數字類型就會報錯

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。