zoukankan      html  css  js  c++  java
  • Fluter基础巩固之Dart语言详解<二>

    继续学习枯燥的Dart语言语法,目前的耐得住寂寞是为了将来学得“爽”做准备的!!!

    异常:

    Dart 提供了 Exception 和 Error 类型, 以及一些子类型。还可以定义自己的异常类型。但是,Dart 代码可以抛出任何非 null 对象为异常,不仅仅是实现了 Exception 或者 Error 的对象。

    Exception类型:

    其中常见的Exception如下:

    Error类型:

    抛出:

    所有的 Dart 异常是非检查异常。 方法不一定声明了他们所抛出的异常, 并且你不要求捕获任何异常【这个Kotlin也差不多】。
    Dart 代码可以抛出任何非 null 对象为异常,不仅仅是实现了 Exception 或者 Error 的对象。

    捕获:

    • 可以使用on 或者 catch 来声明捕获语句,也可以 同时使用。使用 on 来指定异常类型,使用 catch 来 捕获异常对象。
    • catch() 可以带有一个或者两个参数, 第一个参数为抛出的异常对象, 第二个为堆栈信息 (一个 StackTrace 对象)。

      还可以用on来指定异常类型,如下:

      如果抛一个非error的呢?

      还可以用精确异常:

      也能这样写:

      完整的写法可以如下:

    • 可以使用rethrow把捕获的异常重新抛出。

    类:

    构造函数:

    命名构造函数:

    使用命名构造函数可以为一个类实现多个构造函数, 或者使用命名构造函数来更清晰的表明你的意图。

    重定向构造函数:

    一个重定向构造函数是没有代码的,在构造函数声明后,使用冒号调用其他构造函数。

    初始化列表:

    • 在构造函数体执行之前可以初始化实例参数。 使用逗号分隔初始化表达式。
    • 初始化列表非常适合用来设置 final 变量的值。

    调用超类构造函数:

    • 超类命名构造函数不会传递,如果希望使用超类中定义的命名构造函数创建子类,则必须在子类中实现该构造函数。
    • 如果超类没有默认构造函数, 则你需要手动的调用超类的其他构造函数。
    • 调用超类构造函数的参数无法访问 this。
    • 在构造函数的初始化列表中使用 super(),需要把它放到最后。

     

    其中要注意一个细节:

    常量构造函数:

    • 定义const构造函数要确保所有实例变量都是final。
    • const关键字放在构造函数名称之前。

    注意必须是final修饰变量,换成const或去掉都是要报错的:

    有啥用呢?再来看:

    这种写法在未来flutter的学习中会大量运用到的。

    工厂构造函数【用得很多】:

    • 工厂构造函数是一种构造函数,与普通构造函数不同,工厂函数不会自动生成实例,而是通过代码来决定返回的实例对象。
    • 如果一个构造函数并不总是返回一个新的对象,则使用 factory 来定义这个构造函数。
    • 工厂构造函数无法访问this。

     

    要记住这样的写法,因为在未来实际场景中会大量看到~~

    Setter和Getter:

    • 每个实例变量都隐含的具有一个 getter, 如果变量不是 final 的则还有一个 setter。
    • 可以通过实行 getter 和 setter 来创建新的属性, 使用 get 和 set 关键字定义 getter 和 setter。
    • getter 和 setter 的好处是,你可以开始使用实例变量,后来 你可以把实例变量用函数包裹起来,而调用你代码的地方不需要修改。

    代码来瞅一下:

    抽象类:

    • 不能被实例化,除非定义一个工厂构造函数。
    • 抽象类通常用来定义接口, 以及部分实现。
    • 抽象类通常具有抽象方法,抽象方法不需要关键字,以分号结束即可。
    • 接口方式使用时,需要重写抽象类的成员变量和方法,包括私有的。
    • 一个类可以implement一个普通类。Dart任何一个类都是接口
    • 一个类可以implement多个接口。

    比如说按摩可以有多个种类,咱们先来定义一个抽象的按摩类:

    接下来来创建具体的子类,如下:

    调用一下:

    以上就是一种工厂方法的典型使用,需要特别注意:在Dart中木有interface关键字,abstract就可以当接口来用,下面再来看以继承的方式来使用:

    这是第二种工厂模式的写法,对其有个大致印象既可,在之后的实际开发中会有用武之地滴。

    可调用类:

    实现call()方法可以让类像函数一样能够被调用。

    Mixin:

    • 子类没有重写超类A方法的前提下,如果2个或多个超类拥有相同签名的A方法,那么子类会以继承的最后一个超类中的A方法为准。
    • 如果子类自己重写了A方法则以本身的A方法为准。

    下面以这个场景为例:

    下面来看下代码,看mixin是个啥东东?

    void main() {
      Bicycle().transport();
      Motocycle().transport();
      Car().transport();
    }
    
    //交通抽象类
    abstract class Transportation {
      void transport();
    }
    
    //自行车
    class Bicycle extends Transportation {
      String safeIndex() => "low";
    
      String powerUnit() => "2个轮子";
    
      String energy() => "脚蹬";
    
      @override
      void transport() {
        print('Bicycle:
    powerUnit: ${powerUnit()}, safeIndex: ${safeIndex()}, energy: ${energy()}');
      }
    }
    
    //摩托车
    class Motocycle extends Transportation {
      String safeIndex() => "low";
    
      String powerUnit() => "2个轮子";
    
      String energy() => "汽油";
    
      @override
      void transport() {
        print('Motocycle:
    powerUnit: ${powerUnit()}, safeIndex: ${safeIndex()}, energy: ${energy()}');
      }
    }
    
    //汽车
    class Car extends Transportation {
      String safeIndex() => "middle";
    
      String powerUnit() => "4个轮子";
    
      String energy() => "汽油";
    
      @override
      void transport() {
        print('Car:
    powerUnit: ${powerUnit()}, safeIndex: ${safeIndex()}, energy: ${energy()}');
      }
    }

    运行如下:

    好,接下来要改造了,从上面的代码来看:

    好,咱们将里面的行为再单独抽象一下,如下:

    接下来咱们使用Mixin的方式来改造代码:

    void main() {
      Bicycle().transport();
      Motocycle().transport();
      Car().transport();
    }
    
    //交通抽象类
    abstract class Transportation {
      void transport();
    }
    
    //2个轮子
    abstract class TwoWheelTransportation {
      String powerUnit() => "2个轮子";
    }
    
    //4个轮子
    abstract class FourWheelTransportation {
      String powerUnit() => "2个轮子";
    }
    
    //低安全系数
    abstract class LowSafeTransportation {
      String safeIndex() => "low";
    }
    
    //中安全系数
    abstract class MiddleSafeTransportation {
      String safeIndex() => "middle";
    }
    
    //人工动力
    abstract class BodyEnergyTransportation {
      String energy() => "脚蹬";
    }
    
    //汽油动力
    abstract class GasEnergyTransportation {
      String energy() => "汽油";
    }
    
    //自行车
    class Bicycle extends Transportation with LowSafeTransportation, BodyEnergyTransportation, TwoWheelTransportation {
    
      @override
      void transport() {
        print(
            'Bicycle:
    powerUnit: ${powerUnit()}, safeIndex: ${safeIndex()}, energy: ${energy()}');
      }
    }
    
    //摩托车
    class Motocycle extends Transportation with LowSafeTransportation, GasEnergyTransportation, TwoWheelTransportation {
    
      @override
      void transport() {
        print(
            'Motocycle:
    powerUnit: ${powerUnit()}, safeIndex: ${safeIndex()}, energy: ${energy()}');
      }
    }
    
    //汽车
    class Car extends Transportation with MiddleSafeTransportation, GasEnergyTransportation, FourWheelTransportation {
      String safeIndex() => "middle";
    
      String powerUnit() => "4个轮子";
    
      String energy() => "汽油";
    
      @override
      void transport() {
        print(
            'Car:
    powerUnit: ${powerUnit()}, safeIndex: ${safeIndex()}, energy: ${energy()}');
      }
    }

    其运行结果跟之前是一样的:

    这里还涉及到一个顺序问题,下面再来看下:

    调用一下:

    这个结果可以发现:

    这俩打印又能说明啥现象呢?

    这块东东先有个大体印象吧,没有真实的项目做为操练也不可以意会得非常深刻。。

    泛型:

    泛型函数:

    Dart1.21开始可以使用泛型函数。
    泛型函数可以在以下几个地方使用类型参数:
    <1> 函数的返回值类型。
    <2> 参数的类型。
    <3> 局部变量的类型。

    构造函数泛型:

    要在使用构造函数时指定一个或多个类型,可将类型放在类名称后面的尖括号<...>中。

    泛型限制:

    实现泛型类型时,您可能希望限制其参数的类型,可以在<>里面使用extends,其实也就是泛型的协变跟逆变,但是在Dart中木有super限制,如下:

    与Java的区别:

    • Java中的泛型信息是编译时的,泛型信息在运行时是不存在的。
    • Dart的泛型类型是固化的,在运行时也有可以判断的具体类型。

    如何理解?看程序:

    也就是说在Java中,可以测试对象是否为List,但无法测试它是否是List<String>。

    库:

    使用核心库:

    • import 后的必须参数为库 的 URI。(Uniform Resource Identifier统一资源标识符)
    • 对于内置的库,URI 使用特殊的 dart: scheme。
    • 对于其他的库,你可以使用文件系统路径或者 package: scheme。

    载入三方库:

    pubspec.yaml声明需要引用的库,使用Packages get进行拉取。 

    那咱们来找一个三方库来使用一下,先上官网搜一下三方库:

     

    所以咱们将其依赖添加至咱们的工程:

    添加完依赖之后,就可以使用了,如下:

    载入文件:

    如何来引用咱们自己的Dart文件呢?下面新建待引用的Dart文件:

    然后引用一下:

    指定库前缀:

    如果两个库有冲突的标识符,可以为其中一个或两个库都指定前缀,比如:MyLib1.dart 和 MyLib2.dart 都有一个名字为 MyLib 的类, 此时解决冲突就可以指定前缀来解决,如下:

    选择性载入:

    如果只使用库的一部分功能,则可以选择需要导入的内容。 

    下面来演示一下:

    这功能还挺灵活的。。

    延迟载入:

    • 使用 await 关键字暂停代码执行一直到库加载完成。
    • 可提高程序启动速度。
    • 用在不常使用的功能。
    • 用在载入时间过长的包。
    • 执行 A/B 测试,例如 尝试各种算法的 不同实现。

    下面来使用一下,我们在请求完数据之后再来加载文件:

    看下结果:

    感觉Dart好强大呀,值得一学!!!

    自定义库:

    • part 可以把一个库分开到多个 Dart 文件中。
    • 或者我们想让某一些库共享它们的私有对象的时候,可以需要使用part。
    • import不会完全共享作用域,而part之间是完全共享的。如果说在A库中import了B库,B库import了C库,A库是没有办法直接使用C库的对象的。而B,C若是A的part,那么三者共享所有对象。并且包含所有导入。

    啥意思,比如说有三个Dart文件:

     

     而mylib.dart利用part整合了tool.dart和util.dart文件的功能,最终我们使用时只要引用mylib则可以拥有三个文件的功能,如下:

    咱们来试一下:

     

     

    运行:

  • 相关阅读:
    sqlserver调优-索引
    浮点数的这些坑,你未必知道-深入理解浮点数的规律
    生产环境部署springcloud微服务启动慢的问题排查
    redis传输协议规范-下(Redis Protocol specification)
    一步步完成“迷你版” 的ASP.NET Core框架
    安全漏洞整改系列(一)
    docker实战(二)之redis的使用
    docker实战(一)之Tomcat的安装
    docker安装步骤
    WPF后台操作前台元素之查找对象
  • 原文地址:https://www.cnblogs.com/webor2006/p/11981709.html
Copyright © 2011-2022 走看看