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

以上代码会输出如下错误:

Compiler message:
lib/Genericity.dart:14:13: Error: The argument type 'int' can't be assigned to the parameter type 'String'.
  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表达式来判断泛型对象的类型,如:

{ 
	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();		// 走路
}

参考链接:

https://blog.csdn.net/A0x01/article/details/102484528

  • 0
    点赞
  • 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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值