八、Dart中泛型/泛型定义与使用

1. Dart 泛型

1.1 泛型的理解

在 API 文档中你会发现基础数组类型 List 的实际类型是 List<E> 。 <…> 符号将 List 标记为 泛型 (或 参数化) 类型。 这种类型具有形式化的参数。 通常情况下,使用一个字母来代表类型参数, 例如 E, T, S, K, 和 V 等。

泛型:通俗的理解: 就是解决类的接口, 方法, 复用性, 以及对不特定数据类型的支持(类型校验),

在通俗一点,就是对于类型的约束.

1.2 泛型的定义

  1. 使用 <…> 来声明泛型
  2. 通常情况下,使用一个字母来代表类型参数, 例如 ETSK, 和 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;
    }
}

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



作者:时光如剑
链接:https://www.jianshu.com/p/8d9ea88b945c
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Dart 是一种支持泛型的面向对象语言,它允许我们在定义类、函数或方法使用参数化类型。泛型允许我们在不指定具体类型的情况下编写通用的代码,提高代码的重用性和安全性。 在 Dart 泛型的类型变化可分为两种:类型的协变(Covariance)和类型的逆变(Contravariance)。 类型的协变指的是可以将泛型类型的子类型赋值给父类型,这样就可以确保在使用泛型类型时不会发生类型不匹配的错误。例如,如果有一个泛型类 Animal<T>,其 T 是一个类型参数,那么 Animal<Dog> 就是 Animal<Animal> 的子类型。这样我们可以使用 Animal<Animal> 类型的变量来持有 Animal<Dog> 的实例,而不会出现类型错误。 类型的逆变与协变相反,指的是可以将泛型类型的父类型赋值给子类型。这样可以更灵活地使用泛型类型,更好地符合实际的业务需求。例如,如果有一个泛型类 Comparator<T>,其 T 是一个类型参数,那么 Comparator<Animal> 就是 Comparator<Dog> 的父类型。这样我们可以使用 Comparator<Dog> 类型的变量来持有 Comparator<Animal> 的实例,而不会出现类型错误。 泛型的型变在 Dart 使用通配符来表示,泛型类型的协变使用 extends 关键字,逆变使用 super 关键字。例如,在声明一个泛型类型时,我们可以使用 Animal<? extends Animal> 表示协变,使用 Comparator<? super Dog> 表示逆变。这样的声明帮助我们在使用泛型类型时确保类型的正确性。 总结来说,Dart 泛型支持类型的协变和逆变,这样可以更灵活、更安全地使用泛型类型。泛型的型变通过使用通配符、extends 和 super 关键字来表示,使得泛型类型的赋值更加灵活,能够满足不同的业务需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值