美文网首页
Dart(2.2) - 泛型(Generics)

Dart(2.2) - 泛型(Generics)

作者: Longshihua | 来源:发表于2019-04-30 11:38 被阅读0次

    泛型(Generics)

    如果你在API文档寻找基本数组类型或者 List 类型,你将会看到该类型实际上为List<E>,其中<...>标记表示此表为一个泛型类型(或为参数化结构)—— 一种含有正规类型参数的类型。按照惯例,类型变量通常为单字符名称,例如E,T,S,K,以及V。

    为何要使用泛型?

    泛型经常是被要求类型安全的,而且还有很多优势:

    • 合理的指定泛型类型能够更好的生成代码
    • 使用泛型减少重复代码

    如果你打算使用一个仅仅包含字符串的List,你可以声明它为List<String>,通过这种方式,你的程序员同事,以及你的工具(比如Dart编辑器和调试模式下的Dart虚拟机)能检测到将一个非字符串的变量分配到List中很可能是错误的,这里给出一个样例:

    var names = List<String>();
    names.addAll(['Seth', 'Kathy', 'Lars']);
    names.add(42); // Error
    

    另外一个使用泛型的原因是减少重复的代码。 泛型可以在多种类型之间定义同一个实现, 同时还可以继续使用检查模式和静态分析工具提供的代码分析功能。 例如,你创建一个保存缓存对象的接口:

    abstract class ObjectCache {
      Object getByKey(String key);
      void setByKey(String key, Object value);
    }
    

    后来你发现你需要一个用来缓存字符串的实现, 则你又定义另外一个接口:

    abstract class StringCache {
      String getByKey(String key);
      void setByKey(String key, String value);
    }
    

    然后,你又需要一个用来缓存数字的实现, 在后来,你又需要另外一个类型的缓存实现,等等。。。

    泛型可以避免这种重复的代码。 你只需要创建一个接口即可:

    abstract class Cache<T> {
      T getByKey(String key);
      void setByKey(String key, T value);
    }
    

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

    使用集合字面量

    Listset以及map都能被参数化,参数字面量就像你已经见过的常量那样,除非你在左方括号之前添加<type>(对于List)或者<keyType,valuetype>(对于map)。这里有一个使用常量类型的例子:

    var names = <String>['Seth', 'Kathy', 'Lars'];
    var uniqueNames = <String>{'Seth', 'Kathy', 'Lars'};
    var pages = <String, String>{
      'index.html': 'Homepage',
      'robots.txt': 'Hints for web robots',
      'humans.txt': 'We are people, not machines'
    };
    

    使用带构造器的参数化类型

    为了在使用构造器时详细说明一个或多个类型,将类型放入类名后的三角括号(<...>)中,举个例子:

    var nameSet = Set<String>.from(names);
    

    下列代码创建了一个含有整型的键以及值为View的map:

    var views = new Map<int,view>();
    

    泛型集合及其包含的类型

    Dart泛型类型是被具体化的,意思就是它们在整个运行时间中都携带着类型信息。举个例子,你可以测试一个集合中的类型甚至是在生产模式中:

    var names = List<String>();
    names.addAll(['Seth', 'Kathy', 'Lars']);
    print(names is List<String>); // true
    

    限制泛型类型

    当使用泛型类型的时候,你可能想限制泛型的具体类型。 使用extends可以实现这个功能:

    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>();
    

    不指定泛型类型也是可以的

    var foo = Foo();
    print(foo); // Instance of 'Foo<SomeBaseClass>'
    

    如果指定非SomeBaseClass类型将报错

    var foo = Foo<Object>(); // error
    

    使用泛型函数

    一开始,泛型只能在Dart类中使用。 新的语法也支持在函数和方法上使用泛型了

    T first<T>(List<T> ts) {
      // Do some initial work or error checking, then...
      T tmp = ts[0];
      // Do some additional checking or processing...
      return tmp;
    }
    

    这里的 first (<T>)泛型可以在如下地方使用参数 T :

    • 函数的返回值类型 (T)
    • 参数的类型 (List<T>)
    • 局部变量的类型 (T tmp)

    参考

    Dart

    相关文章

      网友评论

          本文标题:Dart(2.2) - 泛型(Generics)

          本文链接:https://www.haomeiwen.com/subject/iwpmnqtx.html