第八节: 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;
    }
}

一旦你更改后在此运行,你会发现报错, 因为此时使用这个类型,泛型只能是字符串类型, 你传入的数字类型就会报错

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341