• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Dart语法学习

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

Dart语法学习

目录

  • 参考资料
  • 语言特性
  • 关键字
  • 变量与常量
  • 数据类型
  • 运算符 operators
  • 控制流程语句
  • 异常 Exceptions
  • 函数 Function
  • 类 Class
  • 类-方法
  • 类-抽象类
  • 类-隐式接口
  • 类-扩展一个类(重写)
  • 库和可见性
  • 异步支持

参考资料

语言特性

  • Dart所有的东西都是对象, 即使是数字numbers、函数function、null也都是对象,所有的对象都继承自Object类。

  • Dart动态类型语言, 尽量给变量定义一个类型,会更安全,没有显示定义类型的变量在 debug 模式下会类型会是 dynamic(动态的)。

  • Dart 在 running 之前解析你的所有代码,指定数据类型和编译时的常量,可以提高运行速度。

  • Dart中的类和接口是统一的,类即接口,你可以继承一个类,也可以实现一个类(接口),自然也包含了良好的面向对象和并发编程的支持。

  • Dart 提供了顶级函数(如:main())。

  • Dart 没有 public、private、protected 这些关键字,变量名以"_"开头意味着对它的 lib 是私有的。

  • 没有初始化的变量都会被赋予默认值 null。

  • final的值只能被设定一次。const 是一个编译时的常量,可以通过 const 来创建常量值,var c=const[];,这里 c 还是一个变量,只是被赋值了一个常量值,它还是可以赋其它值。实例变量可以是 final,但不能是 const。

  • 编程语言并不是孤立存在的,Dart也是这样,他由语言规范、虚拟机、类库和工具等组成:

    • SDK:SDK 包含 Dart VM、dart2js、Pub、库和工具。
    • Dartium:内嵌 Dart VM 的 Chromium ,可以在浏览器中直接执行 dart 代码。
    • Dart2js:将 Dart 代码编译为 JavaScript 的工具。
    • Dart Editor:基于 Eclipse 的全功能 IDE,并包含以上所有工具。支持代码补全、代码导航、快速修正、重构、调试等功能。

关键字(56个)

关键字 - - -
abstract do import super
as dynamic in switch
assert else interface sync
enum implements is this
async export library throw
await external mixin true
break extends new try
case factory null typedef
catch false operator var
class final part void
const finally rethrow while
continue for return with
covariant get set yield
default if static deferred

变量与常量

  1. 变量声明与初始化
  • 调用的变量name包含对String值为“张三” 的对象的引用,name推断变量的类型是String,但可以通过指定它来更改该类型,如果对象不限于单一类型(没有明确的类型),请使用Object或dynamic关键字。
  // 没有明确类型,编译的时候根据值明确类型
  var name = ‘Bob’; 
  Object name = '张三';
  dynamic name = '李四';

  // 显示声明将被推断类型, 可以使用String显示声明字符串类型
  String name = 'Bob' ;
  1. 默认值
  • 未初始化的变量的初始值为null(包括数字),因此数字、字符串都可以调用各种方法
 //测试 数字类型的初始值是什么?
  int lineCount;
  // 为false的时候抛出异常
  assert(lineCount == null);
  print(lineCount); //打印结果为null,证明数字类型初始化值是null
  1. final and const

    • 如果您从未打算更改一个变量,那么使用 final 或 const,不是var,也不是一个类型。 一个 final 变量只能被初始化一次; const变量是一个编译时常量,(Const变量是隐式的final) final的顶级或类变量在第一次使用时被初始化。

    • 被final修饰的顶级变量或类变量在第一次声明的时候就需要初始化。

        // The final variable 'outSideFinalName' must be initialized.
        final String outSideFinalName
    
    • 被final或者const修饰的变量,变量类型可以省略,建议指定数据类型。
    //可以省略String这个类型声明
    final name = "Bob";
    final String name1  = "张三";
    
    const name2 = "alex";
    const String name3 = "李四";
    • 被 final 或 const 修饰的变量无法再去修改其值。
    final String outSideFinalName = "Alex";
    // outSideFinalName', a final variable, can only be set once
    // 一个final变量,只能被设置一次。
    outSideFinalName = "Bill";
    
    const String outSideName = 'Bill';
    // 这样写,编译器提示:Constant variables can't be assigned a value
    // const常量不能赋值
    // outSideName = "小白";
    • flnal 或者 const 不能和 var 同时使用
    // Members can't be declared to be both 'const' and 'var'
    const var String outSideName = 'Bill';
    
    // Members can't be declared to be both 'final' and 'var'
    final var String name = 'Lili';    
    • 常量如果是类级别的,请使用 static const
    // 常量如果是类级别的,请使用 static const
    static const String name3 = 'Tom';
    
    // 这样写保存
    // Only static fields can be declared as const
    // 只有静态字段可以声明为const
    //const String name3 = 'Tom';    
    • 常量的运算
    const speed = 100; //速度(km/h)
    const double distance = 2.5 * speed; // 距离 = 时间 * 速度
    
    final speed2 = 100; //速度(km/h)
    final double distance2 = 2.5 * speed2; // 距离 = 时间 * 速度
    
    • const关键字不只是声明常数变量,您也可以使用它来创建常量值,以及声明创建常量值的构造函数,任何变量都可以有一个常量值。
    // 注意: [] 创建的是一个空的list集合
    // const []创建一个空的、不可变的列表(EIL)。
    var varList = const []; // varList 当前是一个EIL
    final finalList = const []; // finalList一直是EIL
    const constList = const []; // constList 是一个编译时常量的EIL
    
    // 可以更改非final,非const变量的值
    // 即使它曾经具有const值
    varList = ["haha"];
    
    // 不能更改final变量或const变量的值
    // 这样写,编译器提示:a final variable, can only be set once
    // finalList = ["haha"];
    // 这样写,编译器提示:Constant variables can't be assigned a value  
    // constList = ["haha"];
    
    • 在常量表达式中,该运算符的操作数必须为'bool'、'num'、'String'或'null', const常量必须用conat类型的值初始化。
    const String outSideName = 'Bill';
    final String outSideFinalName = 'Alex';
    const String outSideName2 = 'Tom';
    
    const aConstList = const ['1', '2', '3'];
    
    // In constant expressions, operands of this operator must be of type 'bool', 'num', 'String' or 'null'
    // 在常量表达式中,该运算符的操作数必须为'bool'、'num'、'String'或'null'。
    const validConstString = '$outSideName $outSideName2 $aConstList';
    
    // Const variables must be initialized with a constant value
    // const常量必须用conat类型的值初始化
    const validConstString = '$outSideName $outSideName2 $outSideFinalName';
    
    var outSideVarName='Cathy';
    // Const variables must be initialized with a constant value.
    // const常量必须用conat类型的值初始化
    const validConstString = '$outSideName $outSideName2 $outSideVarName';
    
    // 正确写法
    const String outSideConstName = 'Joy';
    const validConstString = '$outSideName $outSideName2 $outSideConstName';
    

数据类型

  1. num

    • num 是数字类型的父类,有两个子类 int 和 double。

    • int 根据平台的不同,整数值不大于64位。在Dart VM上,值可以从-263到263 - 1,编译成JavaScript的Dart使用JavaScript代码,允许值从-253到253 - 1。

    • double 64位(双精度)浮点数,如IEEE 754标准所规定。

    int a = 1;
    print(a);
    
    double b = 1.12;
    print(b);
    
    // String -> int
    int one = int.parse('1');
    // 输出3
    print(one + 2);
    
    // String -> double
    var onePointOne = double.parse('1.1');
    // 输出3.1
    print(onePointOne + 2);
    
    // int -> String
    String oneAsString = 1.toString();
    // The argument type 'int' can't be assigned to the parameter type 'String'
    //print(oneAsString + 2);
    // 输出 1 + 2
    print('$oneAsString + 2');
    // 输出 1 2
    print('$oneAsString 2');
    
    // double -> String 注意括号中要有小数点位数,否则报错
    String piAsString = 3.14159.toStringAsFixed(2);
    // 截取两位小数, 输出3.14
    print(piAsString);
    
    String aString = 1.12618.toStringAsFixed(2);
    // 检查是否四舍五入,输出1.13,发现会做四舍五入
    print(aString);
  2. String

    • Dart里面的String是一系列 UTF-16 代码单元。

    • Dart里面的String是一系列 UTF-16 代码单元。

    • 单引号或者双引号里面嵌套使用引号。

    • 用 或{} 来计算字符串中变量的值,需要注意的是如果是表达式需要${表达式}

    String singleString = 'abcdddd';
    String doubleString = "abcsdfafd";
    
    String sdString = '$singleString a "bcsd" ${singleString}';
    String dsString = "abc 'aaa' $sdString";
    print(sdString);
    print(dsString);
    
    
    String singleString = 'aaa';
    String doubleString = "bbb";
    // 单引号嵌套双引号
    String sdString = '$singleString a "bbb" ${doubleString}';
    // 输出 aaa a "bbb" bbb
    print(sdString);
    
    // 双引号嵌套单引号
    String dsString = "${singleString.toUpperCase()} abc 'aaa' $doubleString.toUpperCase()";
    // 输出 AAA abc 'aaa' bbb.toUpperCase(), 
    可以看出 ”$doubleString.toUpperCase()“ 没有加“{}“,导致输出结果是”bbb.toUpperCase()“
    print(dsString);
  3. bool

    • Dart 是强 bool 类型检查,只有bool 类型的值是true 才被认为是true。
    • 只有两个对象具有bool类型:true和false,它们都是编译时常量。
    • Dart的类型安全意味着您不能使用 if(nonbooleanValue) 或 assert(nonbooleanValue) 等代码, 相反Dart使用的是显式的检查值。
    • assert 是语言内置的断言函数,仅在检查模式下有效在开发过程中, 除非条件为真,否则会引发异常。(断言失败则程序立刻终止)。
     // 检查是否为空字符串
    var fullName = '';
    assert(fullName.isEmpty);
    
    // 检查0
    var hitPoints = 0;
    assert(hitPoints <= 0);
    
    // 检查是否为null
    var unicorn;
    assert(unicorn == null);
    
    // 检查是否为NaN
    var iMeantToDoThis = 0 / 0;
    assert(iMeantToDoThis.isNaN);
    
  4. List集合

    • 在Dart中,数组是List对象,因此大多数人只是将它们称为List。Dart list文字看起来像JavaScript数组文字
     //创建一个int类型的list
    List list = [10, 7, 23];
    // 输出[10, 7, 23]
    print(list);
    
    // 使用List的构造函数,也可以添加int参数,表示List固定长度,不能进行添加 删除操作
    var fruits = new List();
    
    // 添加元素
    fruits.add('apples');
    
    // 添加多个元素
    fruits.addAll(['oranges', 'bananas']);
    
    List subFruits = ['apples', 'oranges', 'banans'];
    // 添加多个元素
    fruits.addAll(subFruits);
    
    // 输出: [apples, oranges, bananas, apples, oranges, banans]
    print(fruits);
    
    // 获取List的长度
    print(fruits.length);
    
    // 获取第一个元素
    print(fruits.first);
    
    // 获取元素最后一个元素
    print(fruits.last);
    
    // 利用索引获取元素
    print(fruits[0]);
    
    // 查找某个元素的索引号
    print(fruits.indexOf('apples'));
    
    // 删除指定位置的元素,返回删除的元素
    print(fruits.removeAt(0));
    
    // 删除指定元素,成功返回true,失败返回false
    // 如果集合里面有多个“apples”, 只会删除集合中第一个改元素
    fruits.remove('apples');
    
    // 删除最后一个元素,返回删除的元素
    fruits.removeLast();
    
    // 删除指定范围(索引)元素,含头不含尾
    fruits.removeRange(start,end);
    
    // 删除指定条件的元素(这里是元素长度大于6)
    fruits.removeWhere((item) => item.length >6);
    
    // 删除所有的元素
    fruits.clear();
    • 注意事项:

      1. 可以直接打印list包括list的元素,list也是一个对象。但是java必须遍历才能打印list,直接打印是地址值。
      2. 和java一样list里面的元素必须保持类型一致,不一致就会报错。
      3. 和java一样list的角标从0开始。
      4. 如果集合里面有多个相同的元素“X”, 只会删除集合中第一个改元素
  5. Map集合

    • 一般来说,map是将键和值相关联的对象。键和值都可以是任何类型的对象。每个键只出现一次,但您可以多次使用相同的值。Dart支持map由map文字和map类型提供。
    • 初始化Map方式一: 直接声明,用{}表示,里面写key和value,每组键值对中间用逗号隔开。
    // Two keys in a map literal can't be equal.
    // Map companys = {'Alibaba': '阿里巴巴', 'Tencent': '腾讯', 'baidu': '百度', 'Alibaba': '钉钉', 'Tenect': 'qq-music'};
    
    Map companys = {'Alibaba': '阿里巴巴', 'Tencent': '腾讯', 'baidu': '百度'};
    // 输出:{Alibaba: 阿里巴巴, Tencent: 腾讯, baidu: 百度}
    print(companys);
    
    • 创建Map方式二:先声明,再去赋值。
    Map schoolsMap = new Map();
    schoolsMap['first'] = '清华';
    schoolsMap['second'] = '北大';
    schoolsMap['third'] = '复旦';
    // 打印结果 {first: 清华, second: 北大, third: 复旦}
    print(schoolsMap);
    
    var fruits = new Map();
    fruits["first"] = "apple";
    fruits["second"] = "banana";
    fruits["fifth"] = "orange";
    //换成双引号,换成var 打印结果 {first: apple, second: banana, fifth: orange}
    print(fruits);
    • Map API
    // 指定键值对的参数类型
    var aMap = new Map<int, String>();
    
    // Map的赋值,中括号中是Key,这里可不是数组
    aMap[1] = '小米';
    
    //Map中的键值对是唯一的
    //同Set不同,第二次输入的Key如果存在,Value会覆盖之前的数据
    aMap[1] = 'alibaba';
    
    // map里面的value可以相同
    aMap[2] = 'alibaba';
    
    // map里面value可以为空字符串
    aMap[3] = '';
    
    // map里面的value可以为null
    aMap[4] = null;
    
    print(aMap);
    
    // 检索Map是否含有某Key
    assert(aMap.containsKey(1));
    
    //删除某个键值对
    aMap.remove(1); 
    
    print(aMap);  
    • 注意事项
      1. map的key类型不一致也不会报错。
      2. 添加元素的时候,会按照你添加元素的顺序逐个加入到map里面,哪怕你的key,比如分别是 1,2,4,看起来有间隔,事实上添加到map的时候是{1:value,2:value,4:value} 这种形式。
      3. map里面的key不能相同。但是value可以相同,value可以为空字符串或者为null。

运算符

描述 操作符
一元后置操作符 expr++ expr-- () [] . ?.
一元前置操作符 expr !expr ~expr ++expr --expr
乘除 * / % ~/
加减 + -
位移 << >>
按位与 &
按位或  
按位异或 ^
逻辑与 &&
逻辑或  
关系和类型判断 >= > <= < as is is!
== !=
如果为空 ??
条件表达式 expr1 ? expr2 : expr3
赋值 = *= /= ~/= %= += -= <<= >>= &= ^= = ??=
级联 ..

流程控制语句(Control flow statements)

  • if...else
  • for
  • while do-whild
  • break continue
  • break continue
  • assert(仅在checked模式有效)

异常(Exceptions)

  1. throw

    • 抛出固定类型的异常
    throw new FormatException('Expected at least 1 section');
    • 抛出任意类型的异常
     throw 'Out of llamas!';
    • 因为抛出异常属于表达式,可以将throw语句放在=>语句中,或者其它可以出现表达式的地方
    distanceTo(Point other) =>
    throw new UnimplementedError();
  2. catch

    • 将可能出现异常的代码放置到try语句中,可以通过 on语句来指定需要捕获的异常类型,使用catch来处理异常。
     try {
        breedMoreLlamas();
    } on OutOfLlamasException {
        // A specific exception
        buyMoreLlamas();
    } on Exception catch (e) {
        // Anything else that is an exception
        print('Unknown exception: $e');
    } catch (e, s) {
        print('Exception details:\n $e');
        print('Stack trace:\n $s');
    }
  3. rethrow

    • rethrow语句用来处理一个异常,同时希望这个异常能够被其它调用的部分使用。
    final foo = '';
    
    void misbehave() {
        try {
        foo = "1";
        } catch (e) {
        print('2');
        rethrow;// 如果不重新抛出异常,main函数中的catch语句执行不到
        }
    }
    
    void main() {
        try {
        misbehave();
        } catch (e) {
        print('3');
        }
    }
  4. finally

    • Dart的finally用来执行那些无论异常是否发生都执行的操作。
    final foo = '';
    
    void misbehave() {
        try {
        foo = "1";
        } catch (e) {
        print('2');
        }
    }
    
    void main() {
        try {
        misbehave();
        } catch (e) {
        print('3');
        } finally {
        print('4'); // 即使没有rethrow最终都会执行到
        }
    }
    

函数 Function

  • 以下是一个实现函数的例子:
 bool isNoble(int atomicNumber) {
     return _nobleGases[atomicNumber] != null;
  }     
  1. main()函数

    • 每个应用程序都必须有一个顶层main()函数,它可以作为应用程序的入口点。该main()函数返回void并具有List参数的可选参数。
    void main() {
    querySelector('#sample_text_id')
        ..text = 'Click me!'
        ..onClick.listen(reverseText);
    }
    
    • 级联符号..允许您在同一个对象上进行一系列操作。除了函数调用之外,还可以访问同一对象上的字段。这通常会为您节省创建临时变量的步骤,并允许您编写更流畅的代码。
    querySelector('#confirm') // Get an object.
        ..text = 'Confirm' // Use its members.
        ..classes.add('important')
        ..onClick.listen((e) => window.alert('Confirmed!'));
    
    • 上述例子相对于:
    var button = querySelector('#confirm');
    button.text = 'Confirm';
    button.classes.add('important');
    button.onClick.listen((e) => window.alert('Confirmed!'));
    
    • 级联符号也可以嵌套使用。 例如:
    final addressBook = (AddressBookBuilder()
    ..name = 'jenny'
    ..email = '[email protected]'
    ..phone = (PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
        .build())
    .build();
    
    • 当返回值是void时不能构建级联。 例如,以下代码失败:
    var sb = StringBuffer();
    sb.write('foo') // 返回void
        ..write('bar'); // 这里会报错
    
    • 注意: 严格地说,级联的..符号不是操作符。它只是Dart语法的一部分。
  2. 可选参数

    • 可选的命名参数, 定义函数时,使用{param1, param2, …},用于指定命名参数。例如:
     //设置[bold]和[hidden]标志
    void enableFlags({bool bold, bool hidden}) {
        // ... 
    }  
    
    enableFlags(bold: true, hidden: false);
    • 可选的位置参数,用[]它们标记为可选的位置参数:
    String say(String from, String msg, [String device]) {
        var result = '$from says $msg';
        if (device != null) {
            result = '$result with a $device';
        }
        return result;
    }
    • 下面是一个不带可选参数调用这个函数的例子:
      say('Bob', 'Howdy'); //结果是: Bob says Howdy
    • 下面是用第三个参数调用这个函数的例子:
     say('Bob', 'Howdy', 'smoke signal'); //结果是:Bob says Howdy with a smoke signal
  3. 默认参数

    • 函数可以使用=为命名参数和位置参数定义默认值。默认值必须是编译时常量。如果没有提供默认值,则默认值为null。
    • 下面是为命名参数设置默认值的示例:
    // 设置 bold 和 hidden 标记的默认值都为false
    void enableFlags2({bool bold = false, bool hidden = false}) {
        // ...
    }
    
    // 调用的时候:bold will be true; hidden will be false.
    enableFlags2(bold: true);
    • 下一个示例显示如何为位置参数设置默认值:
     String say(String from, String msg,
        [String device = 'carrier pigeon', String mood]) {
            var result = '$from says $msg';
            if (device != null) {
                result = '$result with a $device';
            }
            if (mood != null) {
                result = '$result (in a $mood mood)';
            }
            return result;
    }
    
    //调用方式:
    say('Bob', 'Howdy'); //结果为:Bob says Howdy with a carrier pigeon;
    • 您还可以将list或map作为默认值传递。下面的示例定义一个函数doStuff(),该函数指定列表参数的默认list和gifts参数的默认map。
     // 使用list 或者map设置默认值
    void doStuff(
        {List<int> list = const [1, 2, 3],
        Map<String, String> gifts = const {'first': 'paper', 
        'second': 'cotton', 'third': 'leather'
        }}) {
        print('list:  $list');
        print('gifts: $gifts');
    }
  4. 作为一个类对象的功能

    • 您可以将一个函数作为参数传递给另一个函数。
    void printElement(int element) {
        print(element);
    }
    
    var list = [1, 2, 3];
    
    // 把 printElement函数作为一个参数传递进来
    list.forEach(printElement);
    • 您也可以将一个函数分配给一个变量。
     var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
    assert(loudify('hello') == '!!! HELLO !!!');
  5. 匿名函数

    • 大多数函数都能被命名为匿名函数,如 main() 或 printElement()。您还可以创建一个名为匿名函数的无名函数,有时也可以创建lambda或闭包。您可以为变量分配一个匿名函数,例如,您可以从集合中添加或删除它。
    • 一个匿名函数看起来类似于一个命名函数 - 0或更多的参数,在括号之间用逗号和可选类型标注分隔。
    • 下面的代码块包含函数的主体:
    ([[Type] param1[, …]]) { 
        codeBlock; 
    }; 
    • 下面的示例定义了一个具有无类型参数的匿名函数item,该函数被list中的每个item调用,输出一个字符串,该字符串包含指定索引处的值。
     var list = ['apples', 'bananas', 'oranges'];
    list.forEach((item) {
        print('${list.indexOf(item)}: $item');
    });
    • 如果函数只包含一条语句,可以使用箭头符号=>来缩短它, 比如上面的例2可以简写成:
    list.forEach((item) => print('${list.indexOf(item)}: $item'));
  6. 返回值

    • 所有函数都返回一个值,如果没有指定返回值,则语句return null,隐式地附加到函数体。
    foo() {}
    assert(foo() == null);

类(Classes)

  1. 对象

    • Dart 是一种面向对象的语言,并且支持基于mixin的继承方式。
    • Dart 语言中所有的对象都是某一个类的实例,所有的类有同一个基类--Object。
    • 基于mixin的继承方式具体是指:一个类可以继承自多个父类。
    • 使用new语句来构造一个类,构造函数的名字可能是ClassName,也可以是ClassName.identifier, 例如:
     var jsonData = JSON.decode('{"x":1, "y":2}');
    
    // Create a Point using Point().
    var p1 = new Point(2, 2);
    
    // Create a Point using Point.fromJson().
    var p2 = new Point.fromJson(jsonData);
    
    • 使用.(dot)来调用实例的变量或者方法。
    var p = new Point(2, 2);
    
    // Set the value of the instance variable y.
    p.y = 3;
    
    // Get the value of y.
    assert(p.y == 3);
    
    // Invoke distanceTo() on p.
    num distance = p.distanceTo(new Point(4, 4));
    • 使用?.来确认前操作数不为空, 常用来替代. , 避免左边操作数为null引发异常。
     // If p is non-null, set its y value to 4.
    p?.y = 4;  
    • 使用const替代new来创建编译时的常量构造函数。
     var p = const ImmutablePoint(2, 2);
    • 使用runtimeType方法,在运行中获取对象的类型。该方法将返回Type 类型的变量。
     print('The type of a is ${a.runtimeType}');
  2. 实例化变量(Instance variables)

    • 在类定义中,所有没有初始化的变量都会被初始化为null。
     class Point {
        num x; // Declare instance variable x, initially null.
        num y; // Declare y, initially null.
        num z = 0; // Declare z, initially 0.
    }
    • 类定义中所有的变量, Dart语言都会隐式的定义 setter 方法,针对非空的变量会额外增加 getter 方法。
    class Point {
    num x;
    num y;
    }
    
    main() {
        var point = new Point();
        point.x = 4;          // Use the setter method for x.
        assert(point.x == 4); // Use the getter method for x.
        assert(point.y == null); // Values default to null.
    }
  3. 构造函数(Constructors)

    • 声明一个和类名相同的函数,来作为类的构造函数。
      class Point {
        num x;
        num y;
    
        Point(num x, num y) {
            // There's a better way to do this, stay tuned.
            this.x = x;
            this.y = y;
        }
    }
    • this关键字指向了当前类的实例, 上面的代码可以简化为:
     class Point {
        num x;
        num y;
    
        // Syntactic sugar for setting x and y
        // before the constructor body runs.
        Point(this.x, this.y);
    }
  4. 构造函数不能继承(Constructors aren’t inherited)

    • Dart 语言中,子类不会继承父类的命名构造函数。如果不显式提供子类的构造函数,系统就提供默认的构造函数。
  5. 命名的构造函数(Named constructors)

    • 使用命名构造函数从另一类或现有的数据中快速实现构造函数。
    class Point {
        num x;
        num y;
    
        Point(this.x, this.y);
    
        // 命名构造函数Named constructor
        Point.fromJson(Map json) {
            x = json['x'];
            y = json['y'];
        }
    }
    • 构造函数不能被继承,父类中的命名构造函数不能被子类继承。如果想要子类也拥有一个父类一样名字的构造函数,必须在子类是实现这个构造函数。
  6. 调用父类的非默认构造函数

    • 默认情况下,子类只能调用父类的无名,无参数的构造函数; 父类的无名构造函数会在子类的构造函数前调用; 如果initializer list 也同时定义了,则会先执行initializer list 中的内容,然后在执行父类的无名无参数构造函数,最后调用子类自己的无名无参数构造函数。即下面的顺序:

      1. initializer list(初始化列表)
      2. super class’s no-arg constructor(父类无参数构造函数)
      3. main class’s no-arg constructor (主类无参数构造函数)
    • 如果父类不显示提供无名无参数构造函数的构造函数,在子类中必须手打调用父类的一个构造函数。这种情况下,调用父类的构造函数的代码放在子类构造函数名后,子类构造函数体前,中间使用:(colon) 分割。

    class Person {
        String firstName;
    
    Person.fromJson(Map data) {
        print('in Person');
    }
    }
    
    class Employee extends Person {
    // 父类没有无参数的非命名构造函数,必须手动调用一个构造函数     
    super.fromJson(data)
    Employee.fromJson(Map data) : super.fromJson(data) {
        print('in Employee');
    }
    }
    
    main() {
    var emp = new Employee.fromJson({});
    
    // Prints:
    // in Person
    // in Employee
    if (emp is Person) {
        // Type check
        emp.firstName = 'Bob';
    }
    (emp as Person).firstName = 'Bob';
    }
    
  7. 初始化列表

    • 除了调用父类的构造函数,也可以通过初始化列表在子类的构造函数体前(大括号前)来初始化实例的变量值,使用逗号,分隔。如下所示:
    class Point {
    num x;
    num y;
    
    Point(this.x, this.y);
    
    // 初始化列表在构造函数运行前设置实例变量。
    Point.fromJson(Map jsonMap)
    : x = jsonMap['x'],
        y = jsonMap['y'] {
        print('In Point.fromJson(): ($x, $y)');
    }
    }

    注意:上述代码,初始化程序无法访问 this 关键字。

  8. 静态构造函数

    • 如果你的类产生的对象永远不会改变,你可以让这些对象成为编译时常量。为此,需要定义一个 const 构造函数并确保所有的实例变量都是 final 的。
    class ImmutablePoint {
        final num x;
        final num y;
        const ImmutablePoint(this.x, this.y);
        static final ImmutablePoint origin = const ImmutablePoint(0, 0);
    }
    
  9. 重定向构造函数

    • 有时候构造函数的目的只是重定向到该类的另一个构造函数。重定向构造函数没有函数体,使用冒号:分隔。
    class Point {
        num x;
        num y;
    
        // 主构造函数
        Point(this.x, this.y) {
            print("Point($x, $y)");
        }
    
        // 重定向构造函数,指向主构造函数,函数体为空
        Point.alongXAxis(num x) : this(x, 0);
    }
    
    void main() {
        var p1 = new Point(1, 2);
        var p2 = new Point.alongXAxis(4);
    }   
  10. 常量构造函数

    • 如果类的对象不会发生变化,可以构造一个编译时的常量构造函数。定义格式如下:
      • 定义所有的实例变量是final。
      • 使用const声明构造函数。
      class ImmutablePoint {
      final num x;
      final num y;
      const ImmutablePoint(this.x, this.y);
      static final ImmutablePoint origin = const ImmutablePoint(0, 0);
      }
      
  11. 工厂构造函数

    • 当实现一个使用 factory 关键词修饰的构造函数时,这个构造函数不必创建类的新实例。例如,工厂构造函数可能从缓存返回实例,或者它可能返回子类型的实例。 下面的示例演示一个工厂构造函数从缓存返回的对象:
    class Logger {
    final String name;
    bool mute = false;
    
    // _cache 是一个私有库,幸好名字前有个 _ 。 
    static final Map<String, Logger> _cache =  
                           
                        
                        

    鲜花

    握手

    雷人

    路过

    鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
dart的基本语法(一)发布时间:2022-07-14
下一篇:
Dart语言概览发布时间:2022-07-14
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap