美文网首页
二、Dart中方法、类、抽象类、接口、可调用类、混入、异常

二、Dart中方法、类、抽象类、接口、可调用类、混入、异常

作者: 红鲤鱼与绿鲤鱼与驴与鱼 | 来源:发表于2022-05-26 16:09 被阅读0次
    image.png

    1、方法

    1.1 一等方法对象

    在dart 中是面向对象的编程 , num、String、dynamic、这些类型都是一个对象,当然也包括方法(Function)
    看下面的代码, 先定义了一个fun() 方法 ,然后将方法赋值给 Function 变量, 再通过 变量 f 调用

    //这是一个方法
    void fun() {
      debugPrint("这是一个方法");
    }
    
    void main() {
      //方法都是对象,可以赋值给Function变量
      // Function 类,我们将 fun 方法赋值给Function 变量
      Function f = fun;
      //直接调用
      f();
    }
    

    上面的方法 fun() 是没有传参数的,如果我们想传参数应该怎么调用呢

    //这个 参数是一个 Function对象(也就是说可以传入另一个方法,但是这里并没有指定方法的参数与返回值)
    void fun(Function function) {
      debugPrint("这是 fun() 方法");
      //1、注意这个地方调用里面的参数是可以随便填的,因为我们并没有定义都有什么参数和方法的返回值
      function();
    }
    
    void main() {
      //方法都是对象,可以赋值给Function变量
      // Function 类,我们将 fun 方法赋值给Function 变量
      Function f = fun;
      //直接调用
      //2、传入一个匿名函数,这个传入的匿名函数也是可以随便传入参数的
      f((){
        debugPrint("这是参数方法");
      });
    }
    最后输出:
    这是 fun() 方法
    这是参数方法
    

    注意这 1 和 2 的地方(匿名函数和被执行的函数),因为没有定义传入的方法参数和返回值,所以如果两边的参数不一致就会抛出异常(当然编译器是不会报错,只有在运行时才会报错)。 那么这个问题如何解决?
    这就有了 typedef 关键字,它是用来定义一个类型的。看下面这行代码
    typedef void F(String a,int b)
    上面这段代码的意思是:定义了一个 F 的类型,这个F的类型其实就是一个方法, 参数(String,int) 返回值void

    //定义了一个F类型,F 类型其实就是一个方法,参数是(String,int) 返回值是 Void
    typedef void F(String a, int b);
    
    //定义一个方法,些方法的参数 是一个 F 类型
    void fun2(F function) {
      debugPrint("这是 fun2() 方法");
      //因为它是一个F类型,所以在调用的时候要按照我们定义的方法去传参数,而不是和上面一样随便传参
      function("abc", 2);
    }
    
    void main() {
      Function f2 = fun2;
      //调用 fun2() 方法,并且传入匿名函数(这里的参数必须要和上面定义的F类型一样)
      f2((String a, int b) {
        debugPrint("这是 Fun2 方法 $a $b");
      });
    }
    

    当然除了上面这种还有其他的写法,这三种用哪个都行,个人喜欢上面那个

    //直接定义在方法上也是可以的
    void fun3(void Function(String str, int a) function) {
      function("fun3", 123);
    }
    //这两个方法是一样的
    void fun4(void function(String str, int a)) {
      function("fun4", 123);
    }
    
    1.2 可选位置参数

    在Dart中有一些参数是可选得,调用方法的时候即使不传也是可以的
    注意可选位置参数是 有顺序的,如果你想给第二个参数传值,那么前面的必须也要传

    //可选位置参数,可以设置默认参数
    void fun([int? a, int? b = 2]) {
      debugPrint("$a");
      debugPrint("$b");
    }
    
    void main() {
      //这是给第一个参数传值
      fun(10);
      //如果想给第二个参数传就必须保证前面的参数有值
      fun(20,22);
    
    }
    
    1.3 可选命名参数

    调用命名参数时必须要有形参的变量名,而且有了名字就不用在意位置了。不管是命名参数还是位置参数都是可以设置默认值的

    
    //可选命名参数
    void fun2({int i = 1, j = 2}) {
      debugPrint("i=$i;j=$j");
    }
    
      //调用命名参数时必须要有形参的变量名,而且有了名字就不用在意位置了
      fun2(j: 47);
      fun2(i: 35, j: 28);
      fun2(j: 98, i: 73);
    

    2、类

    所有的类都继承Object

    2.1 变量

    在Dart中是没有 private 关键字的, 如果想让一个变量是私有的使用 _ 开头的命名

    class Point {
      //私有变量
      final String _a = "abc";
      int b = 123;
    }
    
    2.2 构造方法
    • 类的构造方法是可以没有方法体的
    • 在Dart中是没有方法重载的,不管是构造方法还是普通的方法
    • 构造方法分为 未命名构造命名构造 ,
    • 未命名构造 只能有一个, 命名构造 可以有多个(只要名字不同即可)
    //类的定义
    class Person {
      // late 关键字表示 延迟初始化,和Kotlin中 lateinit 一个道理
      late String name;
      late int age;
    
      //标准的构造函数
      Person(this.name, this.age);
    
      //在Dart中未命名的构造只能有一个,可以有无数个命名的构造
      Person._() {
        name = "";
        age = 0;
      }
      //命名构造
      Person.a();
    }
    
    2.3 初始化列表

    主要功能就是初始化参数,当然也是可以在构造的方法体中进行初始化的

    class Point {
      String? _a = "abc";
      int b = 123;
      //命名构造
      Point.Map(Map<String, String> map) : _a = map["a"];//初始化参数列表
      void printA() {
        debugPrint("_a:$_a");
      }
    }
    
    void main() {
      Map<String, String> map = {"a": "aah"};
      var p1 = Point.Map(map);
      p1.printA();
    }
    
    2.4 常量构造函数

    在Dart中有两个常量的关键字 const 和 final

    • const 编译时常量
    • final 运行时常量
      const 的性能要比final的要好
    class MyPoint {
      final int x;
      final int y;
    //常量构造函数
      const MyPoint(this.x, this.y);
    }
    
    void main() {
      var p1 = const MyPoint(1, 2);
      var p2 = const MyPoint(1, 2);
      var p3 = const MyPoint(1, 3);
      debugPrint("${p1 == p2}"); // 输出结果为true,注意这两个的参数是一样的,如果不一样就为false
      debugPrint("${p2 == p3}");//参数不一样为false
    }
    
    

    常量构造函数在其他语言中是没有的。在Dart中是很常见的,这是因为在Dart中控件都可以是一个类.比如我们在不同页面中有三个TextView 显示的内容是一样的,那如果使用常量构造函数创建出来的组件就是同一个对象,而不会产生三个对象

    2.5 工厂构造函数 与 静态方法

    工厂构造函数 的关键字是 factory. 必须要有一个构造函数

    class Manager {
      late int i;
      //普通函数
      Manager();
      //工厂构造函数
      factory Manager.get() {
        //调用未命名的构造(但是这个构造必须也要有)
        return Manager();
      }
    }
    //继承
    class Child extends Manager {}
    

    在Dart中静态方法使用 static ,静态方法可以直接使用 类名.方法名() 调用

    class C {
      static print(obj) {
        debugPrint("$obj");
      }
    }
    
    //调用
    void main() {  
      //通过类名直接调用  
      C.print(test);
    }
    
    2.6 Getter 与 Setter 方法

    Dart 语言中的这两个方法都是有对应的 getset 关键字。
    get 方法是没有参数列表的,所以不需要 加括号
    set 方法必须要声明一个参数

    class Child extends Manager {
      int _x = 0;
    
      Child() : super();
    
      int get getX {
        return _x;
      }
    
      set setX(int a) {
        _x = a;
      }
    }
    

    这里当我们调用 set 方法时更像是给变量赋值

      var child = Child();
      child.setX = 1;
      // child.setX(1); 这样写会报错
    
    2.7 操作符重载

    在Kotlin中也有这个功能, 这两个语言使用的关键字是一样的

    class Child  {
      int _x = 0;
     
      int get getX {
        return _x;
      }
    
      set setX(int a) {
        _x = a;
      }
      //返回值和参数可以定义成任何自己需要的类型
      int operator +(Child c) {
        var child = Child();
        child.setX = _x + c.getX;
        return child.getX;
      }}
    

    调用的时候需要注意前面的是调用者后面的是参数

      var child = Child();
      child.setX = 3;
      var child2 = Child();
      child2.setX = 4;
    //这里 child 是调用者,child2 是参数,相当于 child.+(child2)
    int c = child + child2;
      debugPrint("${c}");
    

    下面这个图片是可重载的操作符


    可重载的操作符.png

    3 、抽象类与接口

    3.1 抽象类
    • 使用 abstract 表示 抽象类
    • 抽象类中没有方法体的就是抽象方法
    • 因为构造方法本身是可以省略方法体,所以他不是抽象方法
    abstract class A {
      //构造方法本身可以省略方法体
      A();
    
      //在抽象类中没有方法体的就是抽象方法
      void test();
    
      //有方法体的是实例方法
      void test2() {
        debugPrint("这是 实例方法 test2()");
      }
    }
    
    class B extends A {
      @override
      void test() {
        // TODO: implement test
      }
    }
    
    3.2 接口
    • Dart 中没有 interface 关键字
    • 他的所有的类都可以看做是接口,除了抽象类除外
      在Dart中每个类都隐式的定义了一个包含所有实例成员的接口
    //创建一个普通的类 Test
    class Test {
     //变量
      int x = 0;
     
     //方法
      void fun1() {}
    }
    
    //实现 Test 类
    class MyTest implements Test {
    
      @override
      late int x = 1;
      
      @override
      void fun1() {
        // TODO: implement fun1
      }
    }
    

    4、可调用的类

    如果一个类中有 call() 方法,可直接调用,代码如下

    class MyTest  {
     
    //  可调用的类
      void call() {
        debugPrint("Call 方法");
      }
    }
    
    void main() {
      var test = MyTest();
      //直接调用call
      test();
      //平时这样调用也是可以的
      test.call();
    }
    

    5、混合 mixins

    混合类似是多继承,可以把多个类中的方法混入到新的类中
    如下代码,将A,B混入到C类中

    class A{
      void a(){
        debugPrint("A类的 a() 方法");
      }
      void b(){
        debugPrint("A类的 b() 方法");
      }
    }
    
    class B{
      void b(){
        debugPrint("B类的 b() 方法");
      }
    }
    
    //将A,B混入到C类中
    //注意混入的顺序
    class C with A,B{
      @override
      void a(){
        debugPrint("C类的 a() 方法");
      }
    }
    //如果C类中没有自己的方法的话还可以使用下面的语法糖
    class C = Object with A, B;
    

    注意:

    • A和B 必须是 Object 的直接子类
    • A类和B类不能有构造方法
    • 如果存在重复的方法,会先从C类本身中找,如果找不到再去从最后混入的B 类中去找,然后再是A类

    6、异常

    上面记录了一些类相关的知识,接下来记录一下异常相关
    在Dart中可以抛出任何类型的异常,包括但不限于 int String bool Function
    对,你没有看错还可以抛出一个方法

    //这里的index 动态的数据类型 dynamic
    void _throwException(index){
      if (index == 0) {
        throw "字符串";
      } else if (index == 1) {
        throw 100;
      } else if (index == "2") {
        throw print;
      }
    }
    
    
    void test(){
      print("======");
      try{
        _throwException("2");
    //使用 on 判断 是哪种异常
      }on int catch(e,s){
        print(e);
        print(e.runtimeType);
       }on String catch(e,s){
        print(e);
        print(e.runtimeType);
       }on Function catch(e){
        e("这是一个方法");
        e(e.runtimeType);
      }
    }
    

    相关文章

      网友评论

          本文标题:二、Dart中方法、类、抽象类、接口、可调用类、混入、异常

          本文链接:https://www.haomeiwen.com/subject/kwlkprtx.html