Dart中的泛型

  • 什么是泛型
  • 为什么使用泛型
  • 泛型方法
  • 泛型类
  • 泛型接口
  • 其他
一. 什么是泛型

泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明。
从字面的意思理解来看,泛型,泛就是模糊、暂不确定暂定的意思。可以这样理解,使用泛型就是定义的一个类型,类型暂不确定,给使用给一个占位符给代替,在使用的时候可以给确定其定义的类型。

语法:
Collection_name <data_type> identifier= new Collection_name<data_type>

按照惯例,类型变量有单字母名称,例如E、T、S、K和V。
E, T, K, V是泛型中常用的几个名称,实际上定义泛型时完全可以不使用它们。不过这几个字母用得人多了,也就有了可读性上的意义,这样可以更好的进行协作。

  • E代表Element,元素.
  • T代表Type,类型.
  • K代表Key,键.
  • V代表Value,值.
二. 为什么使用泛型

泛型通常是为了类型安全而必需的,但是它们比仅仅允许您的代码运行有更多的好处:

  • 适当地指定泛型类型会生成更好的代码。
  • 可以使用泛型来减少代码重复。
    dart中所有基本类型数组和列表都是泛型,这样可以提高代码的可读性。
    如果你打算使用一个仅仅包含字符串的List,你可以声明它为List(可理解为“字符串类型组成的List”),通过这种方式,你的程序员同事,以及你的工具(比如Dart编辑器和调试模式下的Dart虚拟机)能检测到将一个非字符串的变量分配到List中很可能是错误的:
var names = new List<String>();   
names.addAll([‘Seth’,’Kathy’,’Lars’]);  
//...   
names.add(42); //在调试模式中失败 (在生产模式中成功).

泛型可以减少代码重复。

// 官网代码
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);
}
三. 泛型方法

泛型方法可以约束一个方法使用同类型的参数、返回同类型的值,可以约束里面的变量类型。

void setData<T>(String key, T value)
{
	print("key=${key}" + " value=${value}");
}

T getData<T>(T value)
{
	return value;
}
 
main(List<String> args)
{ 
	setData("name", "hello dart!"); 	// string类型
	setData("name", 123); 				// int 类型

	print(getData("name"));  			// string类型
	print(getData(123));  				// int 类型
	print(getData<bool>("hello"));		// Error,约束了类型是bool但是传入了String,所以编译器会报错
}
四. 泛型类

声明泛型类,比如声明一个 Array 类,实际上就是 List 的别名,而 List 本身也支持泛型的实现。

class Array<T>
{
	List _list = new List<T>();
	Array();
	void add<T>(T value)
	{
		this._list.add(value);
	}
	get value
	{
		return this._list;
	}
}

main(List<String> args)
{
	List l1 = new List<String>();
	l1.add("aa");
	l1.add("bb");
	print(l1);			// [aa, bb]

	Array arr = new Array<String>();
	arr.add("cc");
	arr.add("dd");
	print(arr.value);	// [cc, dd]

	Array arr2 = new Array<int>();
	arr2.add(1);
	arr2.add(2);
	print(arr2.value);	// [1, 2]
}
五. 泛型接口

下面声明了一个 Storage 接口,然后 Cache 实现了接口,能够约束存储的 value 的类型:

abstract class Storage<T>
{
	Map m = new Map();
	void set(String key, T value);
	void get(String key);
}

class Cache<T> implements Storage<T>
{
	@override
	Map m = new Map();

	@override
	void get(String key)
	{
		print(m[key]);
	}

	@override
	void set(String key, T value)
	{
		m[key] = value;
		print("set successed!");
	}
}

main(List<String> args)
{
	Cache ch = new Cache<String>();
	ch.set("name", "123");
	ch.get("name");
	// ch.set("name", 1232); // type 'int' is not a subtype of type 'String' of 'value'x

	Cache ch2 = new Cache<Map>();
	ch2.set("ptbird", {"name": "pt", "age": 20});
	ch2.get("ptbird"); 
	// ch2.set("name", "23"); // type 'String' is not a subtype of type 'Map<dynamic, dynamic>' of 'value'

	// 执行结果:
	// set successed!
	// 123
	// set successed!
	// {name: pt, age: 20}
}
六. 其他
1.判断泛型对象的类型

可以使用is表达式来判断泛型对象的类型,如:

main(List<String> args)
{ 
	var names = new List<String>();
	print(names is List<String>); 		// true
	print(names is List<int>);			// false
}
2.用于集合类型

List和map字面量也是可以参数化的:

  • 参数化定义list,要在字面量前添加
  • 参数化定义map,要在字面量前添加<keyType, valueType>
    通过参数化定义,可以带来更安全的类型检查,并且可使用变量的自动类型推导,如下:
void main()
{
	// 直接参数化
	var animals = <String>["cat", "dog"];
	var animalMap = <String, String>{
	"cat": "tom",
	"dog": "jerry"
	};
	// 使用构造函数参数化
	var animalList = List<String>();
	var animalMap2 = Map<String, String>();

	animalList.addAll(['bird', 'dog']);
	// 转换成set时,需要指定类型
	var animalSet = Set<String>.from(animalList);
	// 可以直接判定类型
	print(animalList is List<String>); // true
}
3.构造函数中的泛型

在调用构造函数时,可以在类名后使用<…>来指定具体类型,如:

// 构造函数泛型
class Phone<T>
{
	final T mobileNumber;
	Phone(this.mobileNumber);
}

void main()
{
	var p = Phone<String>("123456");
	print(p.mobileNumber);		// 123456
}
4.限制泛型参数类型

当实现一个泛型时,如果需要限制它参数的类型,可以使用extends关键字。

class FootMassage
{
	void doMassage()
	{
		print("走路");
	}
}

// 泛型限制
class Massage<T extends FootMassage>
{
	final T massage;
	Massage(this.massage);
}

void main()
{
	// 泛型限制, 通过extends关键字限定可泛型使用的类型
	var footMassage = FootMassage();
	var m = Massage<FootMassage>(footMassage);
	m.massage.doMassage();		// 走路
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值