1
2
3
void main() {
print("Hello World");
}

变量:使用var声明一个变量,默认为null。

1
2
3
4
5
6
7
8
var number;
// print(number); null

number = 16;
// print(number); 16

number = "111";
// print(number); 111

常量:可以使用final 或 const 进行修饰

1
2
3
4
5
6
7
8
9
10
11
final c = 11;  
// print(c); 11
// c = "2"; The final variable 'c' can only be set once.

const d = 50;
// print(d); 50
// d = 20; Constant variables can't be assigned a value.

// const 和 final 的区别
// const 是一个编译时的常量,final 在第一次使用时被初始化(const 是隐式final ),实例变量可以final,但不能是const。常量如果是类级别的,可以使用static const,例如: static const PI = 3.1415926
// final 只可用来修饰变量,const 关键字即可修饰变量也可用来修饰 常量构造函数

内置类型

  1. Number(数值型):数值型分整形 int 和 浮点型 double,可以用num、int、double 声明 。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    // num 声明的变量加入的是 int 型,还可以被改成 double 型,但是反过来 int 声明的变量不能再赋值成 double 型。

    num a = 10;
    a = 120.9;
    a = 20;

    int c = 10;
    c = 20;
    // c = 20.2; A value of type 'double' can't be assigned to a variable of type 'int'.

    /// ============================= 数值型操作 ==================================

    // 运算符: +、-、*、/、~/、%
    // 常用属性:isNaN、isEven、isOdd 等。
    // 常用方法:round()、floor()、ceil()、toInt()、toDouble()、abs()

    var a = 15;
    var b = 10;
    // print(a + b); 25
    // print(a - b); 5
    // print(a * b); 150
    // print(a / b); 1.5
    // print(a ~/ b); 1
    // print(a % b); 5

    // print(a.isEven); false. 数字是否是偶数
    // print(a.isOdd); true 数字是否是奇数

    var c = 1.23;
    // print(c.floor()); 1 返回小于或等于数字的最大整数
    // print(c.round()); 1 返回舍入到最接近整数的数字的值
    // print(c.ceil()); 2 返回上限值,即大于或等于数字的最小整数
    // print(c.toInt()); 1 返回数字值的整数表示形式
    // print(c.toDouble()); 1.23 返回表示指定Number对象的double值


  2. String(字符串)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    // 使用单引号、双引号创建字符串
    var s = "2222";
    s = '12222';

    // 使用三个引号或双引号创建多行字符串
    s = '''
    12222
    2222
    ''';

    s = "ddd"
    "dddd";

    // 使用r创建原始raw字符串
    s = r'111';

    /// ============================= 数值型操作 ==================================
    // 运算符: +、*、==、[]
    // 插值表达式: ${expression}
    // 常用属性: length、isEmpty、isNotEmpty
    // 常用方法: contains()、subString()、startsWidth()、endWidth()、indexOf()、lastIndexOf()、toLowerCase()、toUpperCase()、trim()、trimLeft()、trimRight()、split()、replaceAll()

    var str1 = "str";
    var str2 = "hello";
    // print(str1 + str2); strhello
    // print(str1 * 2); strstr
    // print(str1 == str2); false

    double price = 12.3;
    // print("价格:$price"); 价格:12.3

    var str = "hello world";
    // print(str.length); 11
    // print(str.isEmpty); false
    // print(str.isNotEmpty); true

    var str = "hello world";
    // print(str.contains("h")); true 判断是字符穿否包含另一个字符串
    // print(str.contains(RegExp(r'A-Z'))); false
    // print(str.substring(1)); ello world 截取字符串
    // print(str.startsWith("hell")); true 以什么开头
    // print(str.endsWith("dl")); false 以什么结尾
    // print(str.indexOf("l")); 2. 指定元素索引(从前往后)
    // print(str.lastIndexOf("l")); 9 指定元素索引(从后往前)
    // print(str.toLowerCase()); hello world. 全小写
    // print(str.toUpperCase()); HELLO WORLD 全大写
    // print(str.trim()); hello world. 去除字符串左右两边的空格
    // print(str.trimLeft()); hello world 去除字符串左边的空格
    // print(str.trimRight()); hello world 去除字符串右边的空格
    // print(str.split(" ")); [hello, world]. 按字符拆分成list
    // print(str.replaceAll("l", "n")); // henno wornd 字符串替换


  3. Boolean(布尔型)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 使用bool表示布尔型
    // bool只有 true 和 false
    // bool 是编译时常量
    // 可以在debug 模式下通过asset断言判断布尔值,如果不为真,会引发异常并终止程序往下运行。

    var a = "";
    assert(a.isEmpty);

    var nullValue;
    assert(nullValue != null);

  4. List(列表)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    // 创建list
    var list = [1, 2, 3];
    var list = [];

    // 创建一个不可变的list
    var list = const [1, 2, 3];

    // 常用方法:length()、add()、insert()、remove()、clear()、indexOf()、lastIndexOf()、sort()、sublist()、asMap()、forEach()、shuffle()

    var list = ["one", "throww", "1111"];
    // print(list.length); 3. list的长度
    list.add("222");
    // print(list); [1111, one, throww, 222] 添加
    list.insert(3, "6")
    // print(list); [1111, one, throww, 222, 6] 插入
    list.remove("1111");
    // print(list); [one, throww, 222, 6] 移出
    list.clear();
    // print(list); [] 清除
    // print(list.indexOf("6")); 查找元素在list的序号,没有找到返回 -1
    // print(list.lastIndexOf("6")); 查找元素在list的序号(倒叙),没有找到返回 -1
    list.sort();
    // print(list); [1111, one, throww] 排序
    // print(list.asMap()); {0: 1111, 1: one, 2: throww} 生成map key是序列上升
    list.forEach((element) {
    // print(element); 1111、one、throww 遍历
    });
    list.shuffle();
    // print(list); [one, throww, 1111]. 随机打乱这个列表的元素

  5. Map(键值对)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // Map 以 key-value (键值对) 形式储存,键和值都可以是任何类型的对象,每个键只出现一次。

    // 直接声明一个Map
    Map game = {"name": "222", "com": "222"};
    // print(game); {name: 222, com: 222}

    // 创建一个不可变的Map, 只需要在Map 前面加入 const
    Map game1 = const {"name": "222", "com": "222"};
    // print(game1); {name: 222, com: 222}

    // 构造方式声明
    Map game2 = Map();
    game2["name"] = "222";
    game2["com"] = "222";
    // print(game2); {name: 222, com: 222}

    // 常用方法:length()、remove()、clear()、forEach()
    Map game = {"name": "222", "com": "222"};
    // print(game.length); 2. Map的长度
    game.remove("name");
    // print(game); {com: 222}
    game.clear();
    // print(game); {}
    game.forEach((key, value) {
    // print("$key --- $value"); name --- 222、com --- 222
    });

  6. Runes(符文)

    • 字符串是一系列字符。Dart 将字符串表示为 Unicode UTF-16 代码单元系列。Unicode 是一种格式,用于为每个字母、数字和符号定义唯一的数值。
    • 由于Dart 字符串是UTF-16 代码单元序列,因此字符串中的32 位Unicode值使用特殊语法表示。符文表示Unicode代码点的整数。
    • dart:core 库中的String类提供了访问符文的机制。可以通过三种方式访问字符串代码单元/符文
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // 使用String.codeUnitAt() 函数,可以通过索引访问字符中的代码单元。返回给定索引处的16位UTF-16代码单元。

    String x = 'Runes';
    // print(x.codeUnitAt(0)); 82

    // String.codeUnits属性, 此属性返回指定字符串的UTF-16代码单元的不可修改列表。
    String x = 'Runes';
    // print(x.codeUnits); [82, 117, 110, 101, 115]

    // String.runes属性,此属性返回此字符串的可迭代Unicode代码点,Runes可迭代扩展。
    String x = 'Runes';
    x.runes.forEach((element) {
    var character = String.fromCharCode(element);
    // print(character); R、u、n、e、s
    });

    // Unicode代码点通常表示为\uXXXX,其中XXXX是4位十六进制值。要指定多于或少于4个十六进制数字,请将值放在大括号中。可以在dart:core库中使用Runes类的构造函数。
    Runes input = new Runes(' \u{1f605} ');
    // print(input); (32, 128517, 32)
    // print(String.fromCharCodes(input)); 😅

  7. Symbols(标识符)

    • Dart中的符号(Symbol)是不透明的动态字符串名称,用于反映库中的元数据。简而言之,符号是一种存储人类可读字符串与优化供计算机使用的字符串之间关系的方法。
    • 反射是一种在运行时获取类型元数据的机制,如类中的方法数,它具有的构造函数数或函数中的参数数。甚至可以调用在运行时加载的类型的方法。
    • 在Dart反射中,dart:mirrors包中提供了特定的类。此库适用于Web应用程序和命令行应用程序。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    // expects a name of class or function or library to reflect
    Symbol obj = Symbol('name');
    // print(obj); Symbol("name"). name必须是有效的公共Dart成员名称,公共构造函数名称或库名称。

    // Foo.dart
    library foo_lib;
    class Foo {
    // class name can be a symbol
    m1() {
    // method name can be a symbol
    print("Inside m1");
    }

    m2() {
    print("Inside m2");
    }

    m3() {
    print("Inside m3");
    }
    }

    // 以下代码在Symbol类型的帮助下加载Foo.dart库并搜索Foo类。由于需要反射上述库中的元数据,因此这里需要代码导入dart:mirrors库

    // main.dart
    import 'dart:mirrors';
    Symbol lib = Symbol('foo_lib'); // //library name stored as Symbol
    Symbol clsToSearch = Symbol("Foo");

    if (chectIfClassAvailableInlibrary(lib, clsToSearch)) {
    // searches Foo class in foo_lib library
    print("class found..");
    }

    bool chectIfClassAvailableInlibrary(Symbol libraryName, Symbol className) {
    MirrorSystem mirrorSystem = currentMirrorSystem();
    LibraryMirror libMirror = mirrorSystem.findLibrary(libraryName);

    if (libMirror != null) {
    print("Found Library");
    print("checkng...class details..");
    print("No of classes found is : ${libMirror.declarations.length}");
    libMirror.declarations.forEach((key, value) {
    print(key); // 将在运行时迭代库中的每个声明,并将声明打印为Symbol的类型。
    });
    if (libMirror.declarations.containsKey(className)) return true;
    return false;
    }
    return false;
    }

    // 输出
    // Found Library
    // checkng...class details..
    // No of classes found is : 1
    // Symbol("Foo")
    // class found..

    ///////////////////////////////////////////////////////////////
    // 显示在类实例方法的数量。可通过使用ClassMirror预定义类来实现。

    // main.dart
    import 'dart:mirrors';
    Symbol lib = Symbol('foo_lib'); // //library name stored as Symbol
    Symbol clsToSearch = Symbol("Foo");
    reflectInstanceMethods(lib, clsToSearch);

    void reflectInstanceMethods(Symbol libraryName, Symbol className) {
    MirrorSystem mirrorSystem = currentMirrorSystem();
    LibraryMirror libMirror = mirrorSystem.findLibrary(libraryName);

    if (libMirror != null) {
    print("Found Library");
    print("checkng...class details..");
    print("No of classes found is : ${libMirror.declarations.length}");
    libMirror.declarations.forEach((key, value) => print(key));

    if (libMirror.declarations.containsKey(className)) print("found class");
    ClassMirror classMirror = libMirror.declarations[className] as ClassMirror;
    print(
    "No of instance methods found is ${classMirror.instanceMembers.length}");
    classMirror.instanceMembers.forEach((key, value) => print(key));
    }
    }

    // 输出
    // Found Library
    // checkng...class details..
    // No of classes found is : 1
    // Symbol("Foo")
    // class found..
    // No of instance methods found is 8
    // Symbol("==")
    // Symbol("hashCode")
    // Symbol("toString")
    // Symbol("noSuchMethod")
    // Symbol("runtimeType")
    // Symbol("m1")
    // Symbol("m2")
    // Symbol("m3")



    /////////////////////////////////////////////////////////////
    // 将Symbol转换为字符串
    Symbol lib = Symbol('foo_lib'); //library name stored as Symbol
    String name_of_lib = MirrorSystem.getName(lib);

    // print(lib); Symbol("foo_lib")
    // print(name_of_lib); foo_lib


    dynamic 和 Object

    • 在Dart 里面,一切皆对象,而且这些对象的父类都是Object。当没有明确类型时,编译的时候会根据值明确类型。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      var name1 = 'abc';
      Object name2 = 'ddd';
      dynamic name3 = '222';

      // 以上写法都可以,但是Dart 不建议这个做。实际开发中我们应尽量为变量确定一个类型,这样做可以提高安全性,加快运行速度。如果不指定类型,则在 debug 模式下类型会是动态的。

      // 推荐
      String s = 'ddd';

    • 使用 dynamic 时则是告诉编译器,我们不用做类型检测,并且知道自己在做什么。如果我们调用一个不存在的方法时,会执行 noSuchMethod() 方法,在默认情况下 (在 Object 里 实现) 它会抛出 “NoSuchMethodError”。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      // 可以编译 
      dynamic obj = "ddd";
      obj["name"] = "123"; // NoSuchMethodError: Class 'String' has no instance method '[]='.

      // 可以使用 as 和 is 关键字对类型进行检测。
      dynamic obj = <String, int>{};
      if (obj is Map<String, int>) {
      obj["obj"] = 12;
      }
      var map = obj as Map<String, int>;
      // print(map); {obj: 12}