[TOC]
Dart2中的泛型同C#大部分都相同,可以按C#的用法来使用(只有小部分语法不同)。
1.创建泛型集合的几种方法
//工厂方法创建泛型集合实例,List<T>为Dart核心库中的类
var list=List<String>.from(['a','b']);
//使用可忽略的new关键字
var list=new List<String>.from(['a','b']);
//使用类型推断
var list=['a','b'];
//使用构造函数,这点与C#不同,List<T>算然是抽象类也可new
var list=new List<string>();
list.addAll(['a','b']);
2.自定义泛型类,泛型方法
class Hello{
void say<T>(){
}
}
//定义泛型类
class MyList<T>{
}
//带约束的泛型类
class HelloList<T extends Hello>{
}
//多种创建实例的方法
var list=new MyList();
var list=MyList();
var list=new HelloList<Hello>();
var list=HelloList<Hello>();
list.say('a');
list.say(1);
mixin
语法定义了一段代码片段,通过混入类的方式来解决无法多继承的问题,有些类似设计模式中的组合功能;dart中任意一个class
都具有mixin
的功能,通过mixin
关键字替换class
来限制常规类仅可作为mixin类型
。
class Animal{}
//会飞的接口定义
class IFly{
void flying(){
print('flying');
}
}
//会游泳的接口帝国一
class ISwim{
void swimming(){
print('swimming');
}
}
//会跑的接口定义
class IRun{
void running(){
print('running');
}
}
//会游泳,飞,跑的鸟
class Birds extends Animal implements ISwim,IFly,IRun{
@override
void flying() {
print('flying');
}
@override
void running() {
print('running');
}
@override
void swimming() {
print('swimming');
}
}
//会跑的老虎
class Tiger extends Animal implements IRun{
@override
void running() {
print('running');
}
}
//会游泳的鱼
class Fish extends Animal implements ISwim{
@override
void swimming() {
print('swimming');
}
}
上面例子我们看到了简答的继承关系,我们实现ISwim,IFly,IRun
接口的时必须要实现接口定义的方法,这些看着似乎有点不爽,因为我们在接口中已经实现了对应的方法,在子类中还要重复实现,所以dart引入了mixin
来解决这个问题。
class Animal{}
//会飞的接口定义
class IFly{
void flying(){
print('flying');
}
}
//会游泳的接口帝国一
class ISwim{
void swimming(){
print('swimming');
}
}
//会跑的接口定义
class IRun{
void running(){
print('running');
}
}
//会游泳,飞,跑的鸟
class Birds extends Animal with ISwim,IFly,IRun{
}
//会跑的老虎
class Tiger extends Animal with IRun{
}
//会游泳的鱼
class Fish extends Animal with ISwim{
}
我们可以看到通过with
替换implements
后的代码,是不是比之前更简洁一些,这就是mixin
带来的混入机制。
让mixin代码跟规范一点
因为dart中class
天生具有mixin
的特性,这里我们做一下简单的修改,使mixin的用法更规范一点。
class Animal{}
//会飞的接口定义
mixin IFly{
void flying(){
print('flying');
}
}
//会游泳的接口帝国一
mixin ISwim{
void swimming(){
print('swimming');
}
}
//会跑的接口定义
mixin IRun{
void running(){
print('running');
}
}
//会游泳,飞,跑的鸟
class Birds extends Animal with ISwim,IFly,IRun{
}
//会跑的老虎
class Tiger extends Animal with IRun{
}
//会游泳的鱼
class Fish extends Animal with ISwim{
}
dart中定义mixin
可以通过on
关键字来限定使用范围
//定义一个有活的的动物,通过on限制只允许继承Anmial类的子类才可以使用Living
mixin Living on Anmial{
void isLivling(){
print('isLiving');
}
}
//现在我们定义一只机器老虎,但玩具老虎是没有生命的,所以不能使用Living,下面代码会报错:
class ToyTiger with Living,IRun{
}
//下面是一个有生命的老虎,所以可以使用Living
class Tiger extends Animal with Living,IRun{
}
mixin TestA{
hello(){
print('TestA');
}
}
mixin TestB{
hello(){
print('TestB');
}
}
class TestExtend{
hello(){
print('TestExtend');
}
}
class Test1 extends TestExtend with TestA,TestB{
hello(){
print('Test1');
}
}
class Test2 extends TestExtend with TestA,TestB{
}
void main(){
Test1().hello(); //Test1
Test2().hello(); //TestB
}
优先级总结:Test1.Hello() > TestB.Hello() > TestA.Hello() > TestExtend.Hello()
dart中使用abstract修饰class来定义抽象类,抽象方法为抽象类中无方法体的方法定义,使用extends来继承抽象方法,抽象类不能使用new创建实例。
//抽象类
abstract class Test{
//抽象方法
void hello();
}
class TestA extends Test{
@override
void hello () {
}
}
dart中只存在隐式接口,即通过implements引入的类或者抽象类都可作为接口,dart要求子类必须实现接口中定义的除构造函数之外的任意成员变量。
class TestA{
void hello()
{
print('TestA.hello');
}
}
abstract class TestB{
hello();
}
//按接口方式实现
class Test1 implements TestA{
@override
void hello () {
print('Test1.Hello');
}
}
//按接口方式实现
class Test2 implements TestB{
@override
void hello () {
print('Test2.Hello);
}
}
dart中每个函数都是Function类型,函数的传递可以使用Function做参数定义,有了Typedefs后就更方便了。
这是一个将函数做为参数传递的例子
void main() {
//该代码段运行正常
Test().acceptFunc(() {
print('hello world!');
});
//该代码段无法正常运行,因为acceptFunc中无法确定参数个数
Test().acceptFunc((String hello) {
print(hello);
});
//该代码段无法正常运行,因为acceptFunc中无法确定参数个数
Test().acceptFunc(helloFunc);
}
String helloFunc(String name) {
print('hello world!');
return name;
}
class Test {
//接受一个函数作为参数,但是无法通过参数类型限制接受什么样的函数
void acceptFunc(Function func) {
if (func != null) {
func();
}
}
}
从上面代码我们很容易发现Function做参数类型的一些限制,比如我们只希望接受无参的函数。幸好dart提供了解决办法,通过Typedefs我们就可以实现。
通过Typedefs限定函数参数的类型
//定义4个typedef类型
typedef void NoArgType();
typedef void OneArgType(String name);
typedef int NoArgAndResultType();
typedef int OneArgAndResultType(String name);
//定义4个方法
void noArgFunc() {
print('noArgFunc');
}
void oneArgFunc(String name) {
print('oneArgFunc');
}
int noArgAndResultFunc(){
print('noArgAndResultFunc');
return 0;
}
int oneArgAndResultFunc(String name) {
print('oneArgAndResultFunc');
return 0;
}
class Test {
//定义4个函数分别接受4种类型的typedef
void acceptNoArgFunc(NoArgType func) {
if (func != null) {
func();
}
}
void acceptOneArgFunc(OneArgType func) {
if (func != null) {
func('Hello World!');
}
}
void acceptNoArgAndResultFunc(NoArgAndResultType func){
if(func!=null){
func();
}
}
void acceptOneArgAndResultFunc(OneArgAndResultType func) {
if (func != null) {
func('Hello World!');
}
}
}
void main() {
//无参无返回值函数
Test().acceptNoArgFunc(() {
print('hello world!');
});
Test().acceptNoArgFunc(noArgFunc);
Test().acceptNoArgFunc(noArgAndResultFunc);
//以下是错误的用法
// Test().acceptNoArgFunc((String name){});
// Test().acceptNoArgFunc(oneArgFunc);
// Test().acceptNoArgFunc(oneArgAndResultFunc);
//无参有返回值函数
Test().acceptNoArgAndResultFunc((){
return 0;
});
Test().acceptNoArgAndResultFunc(noArgAndResultFunc);
//以下是错误的用法
// Test().acceptNoArgAndResultFunc(noArgFunc);
// Test().acceptNoArgAndResultFunc(oneArgFunc);
// Test().acceptNoArgAndResultFunc(oneArgAndResultFunc);
//有参无返回值函数
Test().acceptOneArgFunc((String name){});
Test().acceptOneArgFunc(oneArgFunc);
Test().acceptOneArgFunc(oneArgAndResultFunc);
// 以下是错误的用法
// Test().acceptOneArgFunc(noArgFunc);
// Test().acceptOneArgFunc(noArgAndResultFunc);
//有参有返回值函数
Test().acceptOneArgAndResultFunc((String name)=> 0);
Test().acceptOneArgAndResultFunc(oneArgAndResultFunc);
//以下是错误的用法
// Test().acceptOneArgAndResultFunc(noArgFunc);
// Test().acceptOneArgAndResultFunc(noArgAndResultFunc);
// Test().acceptOneArgAndResultFunc(oneArgFunc);
}
上面的例子中我们定义4种类型的Typedefs,并分辨演示了每种类型的Typedefs在做参数时的用法,最终总结如下:Typedefs定义的类型对入参的验证比较严格,对于返回值为void类型的定义允许接受非void返回值的函数,反过来则不行。