Dart学习笔记(6): 泛型

为什么使用泛型?

泛型常用于需要要求类型安全的情况,但是它也会对代码运行有好处:

  • 适当地指定泛型可以更好地帮助代码生成。
  • 使用泛型可以减少代码重复

比如你想声明一个只能包含 String 类型的数组,你可以将该数组声明为 List<String>(读作“字符串类型的 list”),这样的话就可以很容易避免因为在该数组放入非 String 类变量而导致的诸多问题,同时编译器以及其他阅读代码的人都可以很容易地发现并定位问题:

var names = <String>[];
names.add("jack");
names.add(42); // Error

另一个使用泛型的原因是可以减少重复代码,泛型可以让你在多个不同类型实现之间共享同一个接口声明.比如声明一个方法 返回一个String类型的数据

String getData(String data) {
  return data;
}

此时getData方法只能传入String类型的参数,如果现在要返回一个int类型的数据,又要重新写一个,如下

int getData(int data) {
  return data;
}

这时候可以考虑使用泛型来声明一个类,让不同类型的缓存实现该类做出不同的具体实现即可:

T getData<T>(T data) {
  return data;
}

在上述代码中,T 是一个替代类型。其相当于类型占位符,在开发者调用该接口的时候会指定具体类型。

官网的例子是指定泛型类,具体可以查看Language tour | Dart

//让不同类型的缓存实现该类做出不同的具体实现即可:
abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}

具体实现

class FileCache<T> extends Cache<T> {
  @override
  T getByKey(String key) {
    // TODO: implement getByKey
    throw UnimplementedError();
  }
  @override
  void setByKey(String key, T value) {
    print("写入缓存成功key=$key,value=$value");
  }
}


main() {
  var flieCache = FileCache<String>();//限定指定类型为String
  //此时value传入int类型会提示错误。
  flieCache.setByKey("key",
      123); //The argument type 'int' can't be assigned to the parameter type 'String'
  flieCache.setByKey("key", "value");
}

比如现在需要创建个泛型类,需求是传入任意类型的数据添加到List中

class MyList<T> {
  List list = <T>[]; //创建一个空的数组
  void add(T value) {
    list.add(value); //往数据里添加数据
  }
  void getList() {
    print(list);
  }
}

未指定具体类型的,可以传入任意类型,如下

main() {
  var mylist = MyList();
  mylist.add("jack");
  mylist.add(1);
  mylist.getList();
}
输出打印:[jack, 1]

指定类型,比如我要指定集合中只能添加String类型的数据,可以这么写

main() {
  var mylist = MyList<String>();//指定具体的类型,传入其他类型会报错
  mylist.add("jack");
  mylist.add(1);// 报错:The argument type 'int' can't be assigned to the parameter type 'String'
  mylist.getList();
}

限制参数化类型

有时使用泛型的时候,你可能会想限制可作为参数的泛型范围,也就是参数必须是指定类型的子类,这时候可以使用 extends 关键字。

一种常见的非空类型处理方式,是将子类限制继承 Object (而不是默认的 Object?)。

class Foo<T extends Object> {
  // Any type provided to Foo for T must be non-nullable.
}

除了Object之外,还可以对其他类型使用extends。下面是一个扩展SomeBaseClass的例子,这样SomeBaseClass的成员就可以在T类型的对象上被调用:

class Foo<T extends SomeBaseClass> {
  // Implementation goes here...
  String toString() => "Instance of 'Foo<$T>'";
}

class Extender extends SomeBaseClass {...}

这时候就可以使用 SomeBaseClass 或者它的子类来作为泛型参数:

var someBaseClassFoo = Foo<SomeBaseClass>();
var extenderFoo = Foo<Extender>();
  • 1
    点赞
  • 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
发出的红包

打赏作者

Chen_ShengJie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值