美文网首页
Dart基础(一)

Dart基础(一)

作者: seph_von | 来源:发表于2023-03-16 17:35 被阅读0次

    基础类型

    Number类型

    Number中包含了两个类型intdouble。分别代表整数类型和双精度浮点类型。

    • int
      int 类型在不同的环境中长度并不一样,在DartVM上,int的范围是-2^63 至 2^63 - 1,而在web中,int的范围是-2^53 至 2^53 - 1
      定义int型变量可以通过以下几种方式,其中通过var来定义变量,可以不需要指定类型,编译器可根据字面量进行推断。
    int a = 1;
    int b = 0xDEFF0;
    var c = 2;
    

    注意:通过int类型来定义变量时,如果定义的是全局变量一定要赋值(或声明late),否则编译器会报错。如果是定义局部变量,则在使用前必须赋值,否则使用时会抛出异常。这是因为在dart的空安全机制的限制。

    • double
      double 64位双精度浮点数字。
      定义double变量,可通过以下方式,如果显示的申明变量类型是double,字面量为整形时,必要时会自动转换成double
        var a = 1.0;
        double b = 2.0;
        double c = 1; 
    

    其他

    Number类型的变量都支持基本的运算符+ - * /等,还有ceil() abs() floor()等方法。整型支持传统的位移操作,比如移位(<<>>>>>)、补码 (~)、按位与 (&)、按位或 (|) 以及按位异或 (^)。

    print((3 << 1) == 6); // true; 0011 << 1 == 0110
    print((3 | 4) == 7); // true; 0011 | 0100 == 0111
    print((3 & 4) == 0); // true; 0011 & 0100 == 0000
    

    String

    Dart中的字符串包含了 UTF-16 编码的字符序列。可以使用单引号或者双引号来创建字符串

    var str1 = '我是一个字符串';
    var str2 = "我也是一个字符串"
    

    '"的区别:在'中需要使用\来转义那些与单引号冲突的字符:

    var str1 = 'it\'s easy to escape the string delimiter';
    

    模版字符串

    在字符串中,请以 ${表达式} 的形式使用表达式,如果表达式是一个标识符,可以省略掉 {}。如果表达式的结果为一个对象,则 Dart 会调用该对象的 toString 方法来获取一个字符串。

    var s = 'string interpolation';
    print('Dart has $s, which is very handy.' ==
        'Dart has string interpolation, '
            'which is very handy.'); // true
    print('That deserves all caps. '
            '${s.toUpperCase()} is very handy!' ==
        'That deserves all caps. '
            'STRING INTERPOLATION is very handy!'); // true
    

    字符串字面量是一个编译时常量,只要是编译时常量 (null、数字、字符串、布尔) 都可以作为字符串字面量的插值表达式:

    // 这里定义为常量是可行的
    const aConstNum = 0;
    const aConstBool = true;
    const aConstString = 'a constant string';
    
    // 非常量的字符串是不被允许使用在定义字符串的模版内
    var aNum = 0;
    var aBool = true;
    var aString = 'a string';
    const aConstList = [1, 2, 3];
    
    const validConstString = '$aConstNum $aConstBool $aConstString';
    // const invalidConstString = '$aNum $aBool $aString $aConstList';
    

    字符串拼接

    我们可以使用+号或者并列放置在多行的字符串来拼接字符串。

    var str1 = 'the + operate' + ' works';
    var str2 = 'String '
        'concatenation'
        " works even over line breaks.";
    

    多行字符串

    使用三个' 或者三个"来定义多行字符串

    var s1 = '''
    You can create
    multi-line strings like this one.
    ''';
    var s2 = """This is also a
    multi-line string.""";
    

    raw字符串

    通过在字符串前加上r做前缀可创建raw字符串,即字符串不会被做任何处理(如转义)。

    var s = r'In a raw string, not even \n gets special treatment.';
    print(s); // In a raw string, not even \n gets special treatment.
    

    String与Number类型转换

    下面是字符串与数字类型的转换方式:

    // String -> int
    var one = int.parse('1');
    print(one == 1); // true
    
    // String -> double
    var onePointOne = double.parse('1.1');
    print(onePointOne == 1.1); // true
    
    // int -> String
    String oneAsString = 1.toString();
    print(oneAsString == '1'); //true
    
    // double -> String
    String piAsString = 3.14159.toStringAsFixed(2);
    print(piAsString == '3.14'); //true
    
    

    布尔型

    Dart 使用 bool 关键字表示布尔类型,布尔类型只有两个对象 truefalse,两者都是编译时常量

    Dart的类型安全检查不允许出现一个非bool型的判断,例如if(0) assert(1);

    List

    Dart使用 bool 关键字表示数组类型,字面量是由逗号分隔的一串表达式或值并以方括号 [] 包裹而组成的:

    var lList = [1,2,3]; // 编译器会自动推断出数组的类型List<int>,如果向数组里添加一个非int类型,会报错
    

    在字面量前面加上关键字 const,会定义一个编译时常量,那么就不能执行赋值操作,如:

    var list = const [1,2,3];
    list[1] = 0; // 报错!!
    

    索引

    跟其他语言一样,在Dart里,List的索引也是从0开始的,最后一个元素的索引位置位length-1,可以通过[]来获取对应索引的值。

    var list = [1, 2, 3];
    print(list.length); // 3
    print(list[1]); // 2
    
    list[1] = 1;
    print(list[1]); // 1
    

    扩展符

    Dart提供了 ......?的扩展操作,可以将数组中所有元素插入另一个数组内, 而 ...? 空判断扩展可以避免将null插入到目标数组。

    var list = [1, 2, 3];
    var list2 = [0, ...list];
    print(list2.length); // 4
    print(list2); // [0,1,2,3] 
    
    List? list3 = null;
    var list4 = [0, ...?list3];
    print(list4); // 1
    

    控制语句

    Dart 还同时引入了 集合中的 if 和 集合中的 for 操作,在构建集合时,可以使用条件判断 if和循环 for

    var promoActive = false;
    var nav = ['Home', 'Furniture', 'Plants', if (promoActive) 'Outlet'];
    print(nav); // ['Home', 'Furniture', 'Plants'];
    
    var listOfInts = [1, 2, 3];
    var listOfStrings = ['#0', for (var i in listOfInts) '#$i'];
    print(listOfStrings[1]); // #1
    

    集合

    Dart中使用Set来表示集合类型,它是一组特定集合的无序集合。可以通过字面量{}Set类来定义

    var set = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
    

    Dart 会根据字面量来推断变量是一个Set<String>类型,如果往set对象中添加其他类型的元素,会抛异常

    可以通过在{}前加上类型来定义一个空的集合,或者通过将{}赋值给一个Set类型的变量来实现。

    var set = <String>{};
    Set set2 = {};
    

    Map的字面量语法和Set的字面量语法很接近,因为现有Map的字面量语法,因此{}定义的是一个Map而不是Set,Dart会为{}创建一个Map<dynamic, dynamic>对象。

    常用用法

    • 使用add或者addAll方法向集合中添加元素
    • const定义的常量集合,不能调用add等方法,否则会报错
    • Set支持...扩展,支持if/for控制语句
    • 可以通过length来获取集合的数量

    Map

    Map 是用来关联 keysvalues 的对象。其中键和值都可以是任何类型的对象。每个键只能出现一次但是值可以重复出现多次。 Dart中 Map 提供了 Map 字面量以及 Map 类型两种形式的 Map

    • 通过字面量定义Map
        var gifts = {
          // Key:    Value
          'first': 'partridge',
          'second': 'turtledoves',
          'fifth': 'golden rings'
        };
        var nobleGases = {
            2: 'helium',
            10: 'neon',
            18: 'argon',
        };
    

    Dart 将gifts 推断为Map<String, String>类型,而将nobleGases推断位Map<int, String>类型,如果向其中添加不正确的类型,则会抛出异常。

    • 通过Map类型来定义Map
        var gifts = Map<String, String>();
        gifts['first'] = 'partridge';
        gifts['second'] = 'turtledoves';
        gifts['fifth'] = 'golden rings';
        var nobleGases = Map<int, String>();
        nobleGases[2] = 'helium';
        nobleGases[10] = 'neon';
        nobleGases[18] = 'argon';
    

    Map的常用用法

    • 给Map添加一组键值对,可通过gifts['third']=glasses;
    • 获取Map中的值可以使用gifts['forth'];
    • 判断某个key是否存在使用gifts['sixth']==null;
    • 使用const定义常量的Map时,不可以添加,修改操作
    • Map同样支持... 扩展操作和if/for控制语句

    函数

    Dart是一种真正面向对象的语言,所以即便函数也是对象并且类型为 Function,这意味着函数可以被赋值给变量或者作为其它函数的参数。

    我们可以像这样定义一个函数 :

    bool isNoble(int atomicNumber) {
      return _nobleGases[atomicNumber] != null;
    }
    

    也可以省略 返回类型和参数类型(不建议这样做)

     isNoble(atomicNumber) {
       return _nobleGases[atomicNumber] != null;
    }
    

    如果函数内只包含一个表达式,那么也可以简写成:

    bool isNoble(int atomicNumber)=> _nobleGases[atomicNumber] != null;
    

    语法 => 表达式是 { return 表达式; } 的简写, => 有时也称之为箭头函数; =>后面只能跟表达式,不能跟if判断语句

    参数

    函数的参数主要分两种: 必要参数可选参数。必要参数必须定义在参数列表前面,可选参数定义在必要参数的后面。可选参数可以是「命名的」也可以是「位置的」。

    命名参数

    命名参数默认时可选的,除非使用了required关键字标记。
    命名参数使用 {param1, param2}来定义,如果没有指定默认值,没有required标记,默认值为null

    void enableFlags({bool? bold, bool? hidden}){
        ...
    }
    //使用
    enableFlags(bold:true, hidden:false);
    

    可以使用 = 来给参数指定默认值,指定的默认值必须时一个常量

    void enableFlags({bool bold = false, bool hidden = false}) {...}
    
    // hidden参数位false
    enableFlags(bold: true);
    

    如果希望某个参数时必须要传的,那么就可以使用required来修饰,例如:

    const Scrollbar({super.key, required Widget child});
    

    如果创建一个Scrollbar不包含child的时,编译器就会报错

    required 参数也是可以为null的。

    位置参数

    使用 [] 将一系列参数包裹起来,即可将其标记为位置参数,因为它们的默认值是 null,所以如果没有提供默认值的话,它们的类型必须得是允许为空 nullable 的类型

    String say(String from, String msg, [String? device]) {
      var result = '$from says $msg';
      if (device != null) {
        result = '$result with a $device';
      }
      return result;
    }
    //不使用位置参数调用函数
    print(say('Bob', 'Howdy')); // Bob says Howdy
    //使用位置参数调用函数
    print(say('Bob', 'Howdy', 'smoke signal')); //Bob says Howdy with a smoke signal
    

    可以使用 = 来为一个位置可选参数指定除了 null 以外的默认值。指定的默认值必须要为编译时的常量

    String say(String from, String msg, [String device = 'carrier pigeon']) {
      var result = '$from says $msg with a $device';
      return result;
    }
    
    print(say('Bob', 'Howdy'));  //Bob says Howdy with a carrier pigeon
    

    mian()

    main() 顶级函数作为程序的入口, main() 函数返回值为 void 并且有一个 List<String> 类型的可选参数。

    函数是一级对象

    可以将函数作为参数传递给另一个函数。例如:

    void printElement(int element) {
      print(element);
    }
    
    var list = [1, 2, 3];
    
    // 将printElement作为一个参数
    list.forEach(printElement); // 1 2 3
    

    也可以将函数赋值给一个变量,比如:

    var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
    print(loudify('hello')); // !!! HELLO !!!
    

    匿名函数

    顾名思义,就是没有名字; 通常称为 匿名函数Lambda 表达式Closure 闭包;可以将匿名函数赋值给一个变量然后使用。
    匿名函数的定义如下

    (param1, params2) {
        ...
    }
    

    下面例子就是定义了一个只有一个参数item的匿名函数用来打印List中每个字符串和字符串长度:

    const list = ['apples', 'bananas', 'oranges'];
    list.map((item) {
      return item.toUpperCase();
    }).forEach((item) {
      print('$item: ${item.length}'); // APPLES: 6 BANANAS: 7 ORANGES: 7
    });
    

    运算符

    下表中是常用的运算符,表中从上到下也表示运算符的优先级顺序。

    描述 操作符
    一元后缀 expr++ expr-- () [] ?[] . ?. !
    一元前缀 -expr !expr ~expr ++expr --expr await expr
    乘除运算 * / % ~/
    加减运算 + -
    位移 << >> >>>
    位运算AND &
    位运算异或 ^
    位运算或 |
    关系类型判断 >= > <= < as is is!
    相等 == !=
    逻辑与 &&
    逻辑或
    如果空 ??
    三元运算 expr1 ? expr2 : expr3
    级联 .. ?..
    复合运算 = *= /= += -= &= ^= etc.

    类型判断

    |操作符|含义|
    |--|--|
    |as|类型转换|
    |is|如果对象是指定对象返回true|
    |is!|如果对象是指定对象返回false|

    obj 实现了 T 接口时, obj is T 才会返回 true
    只有当obj明确是某个对象类型时,才使用as

    // 1
    (employee as Person).firstName = 'Bob';
    // 2
    if (employee is Person) {
      // 类型检查
      employee.firstName = 'Bob';
    }
    

    在上面例子中,如果 employeenull 或者不是Person类型时, 注释1处语句就会抛出异常,而注释2处不会抛出异常。

    赋值运算

    ??= 使用场景 obj ??= 123 ,当objnull时,才会赋值 123否则不处理。

    条件表达式

    表达式1 ?? 表达式2

    如果表达式 1 为非 null 则返回其值,否则执行表达式 2 并返回其值

    级联表达式

    级联运算符 .., ?.. 可以在同一个对象上连续调用多个对象的变量或方法

    var paint = Paint()
      ..color = Colors.black
      ..strokeCap = StrokeCap.round
      ..strokeWidth = 5.0;
    

    等同于代码:

    var paint = Paint();
    paint.color = Colors.black;
    paint.strokeCap = StrokeCap.round;
    paint.strokeWidth = 5.0;
    

    如果对象可能为null的话,可以使用?..

    querySelector('#confirm') 
      ?..text = 'Confirm' 
      ..classes.add('important')
      ..onClick.listen((e) => window.alert('Confirmed!'))
      ..scrollIntoView();
    
    

    代码等同于

    var button = querySelector('#confirm');
    button?.text = 'Confirm';
    button?.classes.add('important');
    button?.onClick.listen((e) => window.alert('Confirmed!'));
    button?.scrollIntoView();
    

    级联对象可以嵌套使用:

    final addressBook = (AddressBookBuilder()
          ..name = 'jenny'
          ..email = 'jenny@example.com'
          ..phone = (PhoneNumberBuilder()
                ..number = '415-555-0100'
                ..label = 'home')
              .build())
        .build();
    

    在调用返回对象的函数时,一定要谨慎使用级联操作;如果函数返回void,那么就不能使用级联操作。

    其他运算符

    操作符 含义
    ?[] 判空访问List,不为空时访问List中元素
    ?. 条件访问成员,不为空时访问成员
    断言操作,认为一定不为空访问相关成员,如果为空抛出异常

    控制语句

    if-else

    与其他语言类似,通过条件判断执行代码块 其中 elseelse if 是可选判断。但是判断的条件一定是bool型,不可以是其他类型。

    if(表达式1){
    ...
    }else if(表达式2){
    ...
    }else{
    ...
    }
    

    for循环

    • 可以使用标准的for循环进行迭代
      for(int i=0; i<10; i++)
    • 使用for-in方法遍历一个可迭代的对象
      for(final a in objs)
    • 使用可迭代对象的forEach方法
      iteractor.forEach()

    while 和 do-while循环

    whiledo-while的区别是:

    • while会先进行判断,然后再执行代码块,
    • do-while是先执行代码块,再进行判断

    contin 和 break

    continue 表示跳过此次循环,break表示跳出循环

    如果在Iterable对象中,可以使用where代替continue

    candidates
        .where((c) => c.yearsExperience >= 5)
        .forEach((c) => c.interview());
    

    switch-case

    Switch 语句在Dart中使用 == 来比较整数、字符串或编译时常量,比较的两个对象必须是同一个类型且不能是子类并且没有重写 == 操作符。 枚举类型非常适合在 Switch 语句中使用。

    非空case想要实现穿透可通过continue来实现:

    var command = 'CLOSED';
    switch (command) {
      case 'CLOSED':
        executeClosed();
        continue nowClosed;
    
      nowClosed:
      case 'NOW_CLOSED':
        executeNowClosed();
        break;
    }
    

    每个case内都可以有局部变量,并且只在当前case可见。

    注释

    单行注释

    单行注释以//开始,所在行的内容都属于注释内容

    // 这是一个单行注释
    

    多行注释

    多行注释以/*开头,以*/结尾,在/**/之间的内容都会被编译器忽略,认为是注释内容

    /*
    这是一个多行注释
    注释第二行内容
    ...
    */
    
    /*
    嵌套注释的外层
      /*
        嵌套注释内层
      */
    嵌套注释外层
    */
    

    文档注释

    文档注释使用/// 或者是/**,多个连续///注释与多行注释效果一致。多行文档注释,编译器会忽略注释的内容,但是如果使用了[],则编译器会产生引用括号内的内容如类、方法、字段、顶级变量、函数和参数。

    ///这是一个文档注释举例
    ///如果使用了中括号,则会解析括号内容,引用相关内容[feed]
    

    上面举例中[feed]将会生成一个链接,指向feed的方法文档

    相关文章

      网友评论

          本文标题:Dart基础(一)

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