Dart

泛型——Dart(五)

2020-02-22  本文已影响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类型

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

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

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 等等可以随便写,但是还是有一些默认的规范:

List<E>

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

泛型接口

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}';
  }
}

上一篇 下一篇

猜你喜欢

热点阅读