美文网首页Dart
泛型——Dart(五)

泛型——Dart(五)

作者: 向日花开 | 来源:发表于2020-02-22 07:30 被阅读0次

泛型

从字面意思理解,就是广泛的类型,我们可以在集合中看到泛型的影子:

abstract class List<E> implements EfficientLengthIterable<E> {
  ...
}

为什么要有泛型?

以集合为例,假如没有泛型,那么 List 要存储某一指定类型的数据是不是就要单独维护一个 List 类,比如 List 存放 int,存放 String,存放自定义的类 Person 等等,没有泛型的情况下那是不是要维护无数个 List。当然我们可以不用维护无数个,我们把 List 存放的类型换为 dynamic 或者 Object,在取数据的时候强转一下也是可以的。但是!!!我们来看看以下分别用 Object,dynamic,和泛型来存储数据的例子:

实体类
//实体类
class Person {
  String name;

  Person(this.name);
}
以 Object 类型存放
//存放Object的类
class CacheObj {
  //存放一个Object类型数据data
  Object _data;

  Object get data => _data;

  set data(Object value) {
    _data = value;
  }
}
以 dynamic 存放
//存放一个动态类型的类
class CacheDynamic {
  //存放一个dynamic类型数据data
  dynamic _data;

  dynamic get data => _data;

  set data(dynamic value) {
    _data = value;
  }
}

以泛型存放

//存放泛型T的类
class CacheType<T> {
  //存放一个T 类型的数据 data

  T _data;

  T get data => _data;

  set data(T value) {
    _data = value;
  }
}

调用运行
    Person person = new Person("小明");

    CacheObj cacheObj = new CacheObj();
    cacheObj.data = person;
    //print("CacheObj===>" + cacheObj.data.name); //编译不通过

    print("CacheObj===>" + (cacheObj.data as Person).name); //编译通过,正常打印

    CacheDynamic cacheDynamic = new CacheDynamic();
    cacheDynamic.data = person;
    print("CacheDynamic===>" + cacheDynamic.data.name); //编译通过,正常打印,

    // 但是这有很大的隐患,因为这里它不做类型检查,意味着我们写别的属性也是能编译通过的,例如:
    print("CacheDynamic===>" + cacheDynamic.data.age); //编译通过,但是运行肯定报错了,
    //这就给程序带来很大的隐患,而且这种问题还不太容易发现

    CacheType<Person> cacheType = new CacheType();
    cacheType.data = person;
    print("CacheType===>" + cacheType.data.name);//愉快的正常打印,而且编译器知道取出来的数据就是Person类型

所以从以上来看,泛型很重要,它能

  • 提高代码复用性。比如上面的 CacheType 类它不止能存放 Person 类,也能存放其他数据类型,当然啦,其它两个类也是可以做到的,但这里就只强调泛型类。

光是这点就已经很厉害,很实(niu)用(bi)了,它能提高类,接口,方法的复用性,以及对不特定数据类型的支持,比如上面存放的数据类型 Person。

  • 相比于 Object, dynamic 来说泛型能够检查类型,约束类型。比如上面的
CacheType<Person>

它只能存放 Person 类型的数据,同时呢,取出来的数据类型也是 Person,不像 dynamic 太过奔放,也不像 Object 太过麻烦。

多泛型

上面的 CacheType 仅仅只能存放一种类型的数据,如果我们想存放更多种类型的数据,我们可以这样:

//存放多种类型的数据
class CacheTpyes<T1, T2, T3> {
  T1 _data1;

  T2 _data2;

  T3 _data3;

  T1 get data1 => _data1;

  set data1(T1 value) {
    _data1 = value;
  }

  T2 get data2 => _data2;

  set data2(T2 value) {
    _data2 = value;
  }

  T3 get data3 => _data3;

  set data3(T3 value) {
    _data3 = value;
  }
}

泛型的规范

虽然泛型可以随便写,如,T,T1,T2,B1,H1 等等可以随便写,但是还是有一些默认的规范:

  • E — Element,如:
List<E>
  • K,V — Key,Value,代表 Map 的键值对

  • N — Number,数字

  • T — Type,类型,如 String,Integer 等等

泛型接口,泛型类,泛型方法

泛型接口

dart 中一般用抽象类来表示接口。

/**
 * 格式:接口名后面跟 <T>
 *
 * @param <T>
 */
abstract class IManager<T> {
  void add(T data);

  T get(int index);

  void sop();
}
泛型类

之前就定义过,现在写一个实现泛型接口的泛型类。

/**
 * 实现了IManager泛型接口的泛型类
 */
class Manager<T> implements IManager<T> {
  //数据集合
  List<T> _datas;

  //构造
  Manager() {
    _datas = new List();
  }

  //泛型方法,
  @override
  void add(T data) {
    // TODO: implement add
    _datas.add(data);
  }


  //泛型方法,
  @override
  T get(int index) {
    // TODO: implement remove
    return _datas[index];
  }

  @override
  void sop() {
    // TODO: implement sop
    for (T t in _datas) {
      print(t.toString());
    }
  }
}
泛型方法
  //泛型方法,
  @override
  void add(T data) {
    // TODO: implement add
    _datas.add(data);
  }


  //泛型方法,
  @override
  T get(int index) {
    // TODO: implement remove
    return _datas[index];
  }

案例运行


    Manager<Person> manager = new Manager<Person>();
    manager.add(new Person("小鱼"));
    manager.add(new Person("小黑"));
    manager.add(new Person("SF"));

    print("get--->" + manager.get(1).name);

    manager.sop();

确定上限

字面意思就是你的上限我已经给你定好了,你不可能再超出这个范围,那就有用到一个关键字 extends,我们让 T(泛型)extends 某一个类,那是不是这个泛型的上限就被你决定了。
下面我们看代码。

///有时候你在实现类似通用接口的泛型中,期望的类型是某些特定类型时,这时可以使用类型约束
class Member<T extends Person> {
  T _person;

  ///泛型作用:约束参数类型
  Member(this._person);

  @override
  String toString() {
    return 'Member{_person: $_person}';
  }

}

约束 Member 类型只能接受 Person 子类型的数据。

最后

贴一张自己学习Flutter的公众号,感兴趣的小伙伴可以一起学习哦。。。

全部代码

import 'dart:ffi';

import 'package:flutter/material.dart';
import 'package:flutter_travel/pages/dart_pages/dart_oop_page.dart';

class DartGenericPage extends StatefulWidget {
  @override
  _DartGenericPageState createState() => _DartGenericPageState();
}

class _DartGenericPageState extends State<DartGenericPage> {
  List<dynamic> datas = new List();

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    datas.add("11111");
    datas.add(2);
    datas.add(3.444);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Dart泛型"),
      ),
      body: Center(
        child: Material(
          child: InkWell(
            onTap: () {
              print(datas.toString());
              //_showT1();
              _showT2();
            },
            child: Container(
              alignment: Alignment.center,
              height: 50,
              width: 200,
              decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(5),
                  gradient: LinearGradient(colors: [
                    Theme.of(context).primaryColor.withOpacity(.5),
                    Theme.of(context).primaryColor.withOpacity(.7),
                  ])),
              child: Text(
                "点击运行",
                style: TextStyle(color: Colors.white, fontSize: 16),
              ),
            ),
          ),
        ),
      ),
    );
  }

  _showT1() {
    Person person = new Person("小明");

    CacheObj cacheObj = new CacheObj();
    cacheObj.data = person;
    //print("CacheObj===>" + cacheObj.data.name); //编译不通过

    print("CacheObj===>" + (cacheObj.data as Person).name); //编译通过,正常打印

    CacheDynamic cacheDynamic = new CacheDynamic();
    cacheDynamic.data = person;
    print("CacheDynamic===>" + cacheDynamic.data.name); //编译通过,正常打印,

    // 但是这有很大的隐患,因为这里它不做类型检查,意味着我们写别的属性也是能编译通过的,例如:
    print("CacheDynamic===>" + cacheDynamic.data.age); //编译通过,但是运行肯定报错了,
    //这就给程序带来很大的隐患,而且这种问题还不太容易发现

    CacheType<Person> cacheType = new CacheType();
    cacheType.data = person;
    print("CacheType===>" +
        cacheType.data.name); //愉快的正常打印,而且编译器知道取出来的数据就是Person类型
  }

  _showT2() {
    Manager<Person> manager = new Manager<Person>();
    manager.add(new Person("小鱼"));
    manager.add(new Person("小黑"));
    manager.add(new Person("SF"));

    print("get--->" + manager.get(1).name);

    manager.sop();
  }
}

//存放Object的类
class CacheObj {
  //存放一个Object类型数据data
  Object _data;

  Object get data => _data;

  set data(Object value) {
    _data = value;
  }
}

//存放一个动态类型的类
class CacheDynamic {
  //存放一个dynamic类型数据data
  dynamic _data;

  dynamic get data => _data;

  set data(dynamic value) {
    _data = value;
  }
}

//存放泛型T的类
class CacheType<T> {
  //存放一个T 类型的数据 data

  T _data;

  T get data => _data;

  set data(T value) {
    _data = value;
  }
}

//实体类
class Person {
  String name;

  Person(this.name);

  @override
  String toString() {
    return 'Person{name: $name}';
  }
}

//存放多种类型的数据
class CacheTpyes<T1, T2, T3> {
  T1 _data1;

  T2 _data2;

  T3 _data3;

  T1 get data1 => _data1;

  set data1(T1 value) {
    _data1 = value;
  }

  T2 get data2 => _data2;

  set data2(T2 value) {
    _data2 = value;
  }

  T3 get data3 => _data3;

  set data3(T3 value) {
    _data3 = value;
  }
}

/**
 * 格式:接口名后面跟 <T>
 *
 * @param <T>
 */
abstract class IManager<T> {
  void add(T data);

  T get(int index);

  void sop();
}

/**
 * 实现了IManager泛型接口的泛型类
 */
class Manager<T> implements IManager<T> {
  //数据集合
  List<T> _datas;

  //构造
  Manager() {
    _datas = new List();
  }

  //泛型方法,
  @override
  void add(T data) {
    // TODO: implement add
    _datas.add(data);
  }

  //泛型方法,
  @override
  T get(int index) {
    // TODO: implement remove
    return _datas[index];
  }

  @override
  void sop() {
    // TODO: implement sop
    for (T t in _datas) {
      print(t.toString());
    }
  }
}

///有时候你在实现类似通用接口的泛型中,期望的类型是某些特定类型时,这时可以使用类型约束
class Member<T extends Person> {
  T _person;

  ///泛型作用:约束参数类型
  Member(this._person);

  @override
  String toString() {
    return 'Member{_person: $_person}';
  }
}

相关文章

  • 泛型——Dart(五)

    泛型 从字面意思理解,就是广泛的类型,我们可以在集合中看到泛型的影子: 为什么要有泛型? 以集合为例,假如没有泛型...

  • Dart 泛型

    解决类、接口、方法的复用性以及对不特定数据类型的支持(类型校验) 这种输出指定的类型,可以使用泛型解决 字母 T ...

  • dart语言学习笔记-4

    泛型 Dart的泛型会一直保留到运行时 Libraries & visibility import和library...

  • Dart 泛型 泛型类 泛型接口

    视频地址https://www.bilibili.com/video/av52490605?p=13 泛型就是解决...

  • Dart基础(八)-泛型

    1.简介:   Dart语言是强类型语言,强类型语言都支持泛型Generics。那么什么是泛型呢?泛型是指代码在使...

  • Dart 泛型 泛型方法 泛型类 泛型接口

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

  • 带你Dart带你Diao之泛型

    泛型学过Java的都应该比较熟悉了,Dart的泛型和Java泛型的核心理念都差不多,在使用中略有不同。 1.使用泛...

  • Dart学习-泛型

    如果在API文档上查看基本数组类型List,你会发现该类型实际上是List ,其中<...>注解标记这次集合...

  • Dart -- 泛型(Generics)

    如果您查看基本数组类型List的API文档,您将看到该类型实际上是List。<...>符号标记列表为泛型(或...

  • Flutter/Dart - 泛型

    泛型的定义 通俗理解:泛型就是解决类,接口,方法的复用性、以及对不特定数据类型的支持(类型校验) 接下来我们实现一...

网友评论

    本文标题:泛型——Dart(五)

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