前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 ># 泛型

# 泛型

作者头像
用户1175783
发布2019-09-10 14:41:57
7530
发布2019-09-10 14:41:57
举报
文章被收录于专栏:用户1175783的专栏

[TOC]

# 泛型

​ Dart2中的泛型同C#大部分都相同,可以按C#的用法来使用(只有小部分语法不同)。

1.创建泛型集合的几种方法

代码语言:javascript
复制
//工厂方法创建泛型集合实例,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.自定义泛型类,泛型方法

代码语言:javascript
复制
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用法

mixin语法定义了一段代码片段,通过混入类的方式来解决无法多继承的问题,有些类似设计模式中的组合功能;dart中任意一个class都具有mixin的功能,通过mixin关键字替换class来限制常规类仅可作为mixin类型

# 动物类型继承关系例子

代码语言:javascript
复制
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来解决这个问题。

# 通过mixin解决多继承的限制

代码语言:javascript
复制
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的用法更规范一点。

代码语言:javascript
复制
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{
}

# 限制mixin类型的使用范围

​ dart中定义mixin可以通过on关键字来限定使用范围

代码语言:javascript
复制
//定义一个有活的的动物,通过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类型优先级问题

代码语言:javascript
复制
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()

# mixin的语法限制

  1. mixin仅作为一个代码片段存在,它不能直接被调用,需要通过with混入其它class后才有意义
  2. mixin可以通过on来限制使用范围
  3. class默认据用mixin的特性,通过使用mixin关键字替换class可以定义一个仅具有mixin功能的代码片段
  4. mixin不能使用extends但可以使用implements。

# 面向对象(类,抽象类,接口,getter/setter访问器)

# 抽象类

​ dart中使用abstract修饰class来定义抽象类,抽象方法为抽象类中无方法体的方法定义,使用extends来继承抽象方法,抽象类不能使用new创建实例。

代码语言:javascript
复制
//抽象类
abstract class Test{
    //抽象方法
    void hello();
}

class TestA extends Test{
  @override
  void hello () {
  }
}

# 接口

​ dart中只存在隐式接口,即通过implements引入的类或者抽象类都可作为接口,dart要求子类必须实现接口中定义的除构造函数之外的任意成员变量。

代码语言:javascript
复制
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);
  }
}

#

# 构造函数
  1. 每个class中都有一个默认无参构造函数 class Test{} //等效如下: class Test{ Test(); }
  2. 要定义多个构造函数必须使用命名构造函数 class Test{ Test(); //不允许存在同名构造函数,即使参数不同也不可以 //Test(String name); //下面定义了两个命名构造函数 Test.noArg(); Test.oneArg(String name); }
  3. 如果一个类定义了一个以上的非默认构造函数,则默认构造函数就不会被定义。 class Test{ Test(String name); } //因为定义了有参构造函数,所以默认构造函数就是失去了意义 //正确的用法 new Test('name'); //错误的用法,因为存在其它构造函数 Test();
  4. 子类必须实现父类中至少一个构造函数 class TestA{ Test.noArg(); Test.OneArg(); } class Test1 extends TestA{ //因为TestA中没有默认构造函数,所以必须至少实现父类的一个构造函数 Test1.noArg():super.noArg(); }
  5. 构造函数无法被子类继承 class TestA{ Test.noArg(); Test.OneArg(String name); } class Test1 extends TestA{ Test1.noArg():super.noArg(); } //因为构造函数不能不继承,所以无法调用父类的构造函数 //错误的用法,Test1只实现了noArg构造函数,所以只能调用noArg构造函数 Test1().oneArg();
  6. 子类构造函数如果不指定调用父类哪个构造函数,且父类存在默认构造函数,则子类被实例化时一定会调用父类的默认构造函数。 class TestA{ Test(){ print('TestA'); } } class Test1 extends TestA{ Test1(){ print('Test1'); } } //父类的构造函数先执行 new Tesst1(); //TestA //Test1
# 工厂构造函数
  1. 工厂构造函数属于构造函数的一种特殊用法,构造函数不需要返回值,但是工厂构造函数必须返回该类的实例,使用方式同构造函数没有区别。
  2. 工厂构造函数类似设计模式中的工厂方法,但不能使用this关键字有点类似静态方法的限制(实际就是dart的语法糖)。
  3. 需要使用factory来定义工厂构造函数。 class Test{ final String name; factory Test(String name){ print(name); return Test._oneArg(name); } Test._oneArg(this.name); }
# 函数
  1. dart不支持函数重载,也就是说不能存在相同名称的函数。
  2. dart函数名成必须是以小写字母开头。

# Typedefs(委托)

​ dart中每个函数都是Function类型,函数的传递可以使用Function做参数定义,有了Typedefs后就更方便了。

这是一个将函数做为参数传递的例子

代码语言:javascript
复制
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限定函数参数的类型

代码语言:javascript
复制
//定义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返回值的函数,反过来则不行。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-05-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # 泛型
  • # mixin用法
    • # 动物类型继承关系例子
      • # 通过mixin解决多继承的限制
        • # 限制mixin类型的使用范围
          • # 有相同成员的mixin类型优先级问题
            • # mixin的语法限制
            • # 面向对象(类,抽象类,接口,getter/setter访问器)
              • # 抽象类
                • # 接口
                  • # 类
                    • # 构造函数
                    • # 工厂构造函数
                    • # 函数
                • # Typedefs(委托)
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档