基本语法

两种 main 方法的定义

    main() {
        print("drat demo 12312");
    }

    // 无返回值方法
    void main() {
        print("dasdas");
    }

数据类型定义

  var w = 12312;
  // w = 'dasdas'; // 报错,类型已经被推导,无法重新赋值
  w = 43534;
  print(w);

  int w1 = 12312;
  w = 3242342;
  print(w);

  double w = 10; // 浮点型可以声明整形
  print(w); // 10.0

  int q = 10.2; // 整形不可声明浮点型

  String str = '12312';
  str = '1231231';
  print(str);

  const w = '12312';
  // w = '312312'; // 报错,const 不能被重新赋值
  print(w);

  // 字符串相加
  var w = '12312';
  w = w + '-- 12312';
  // w = w - '2'; // 不可减法
  print(w);

  // 多行文本拼接
  w = ''' 123123
      dasdasdasdas
  ''';

  var q = 'value is: $w'; // 字符串模版使用 $xxx 声明;

  print('$w $q');

  var qq = DateTime.now(); // var 也是运行时变量
  print(qq);

  var q2 = DateTime.now;

  print(''' $w --- $q ----- $DateTime $q2''');

  bool a;  // bool 类型
  a = true;
  print(a);

  if (a) {  // if else 语句
    print(1);
  } else {
    print(2);
  }

  final w;
  w = 123123;
  // w = 423423423; // 报错 final 只能被赋值一次,可以在初始化时不给值;
  print(w);

  // const 在创建时,就需要赋值不可改变。final 创建时可以不赋值,后续只能赋值一次。
  // const、final 最大的区别:cons 是编译时,final 是运行时(惰性)在代码运行到时,才确定值的类型
  final dates = new DateTime.now();
  print(dates);

  const dates2 = new DateTime.now(); // 报错,因为 const 是编译时,编译时无法确定返回值的类型,因此报错。

list 类型

基础使用

  var q = [1, '2', '', 4];
  print(q); // 打印数组
  print(q.length); // 集合长度
  print(q[1]); // 获取数组指定位置值
  q.add('dasdas'); // push 数据
  print(q);

  // 不论是 const 还是 final 都可以支持定义数组后修改
  final w = [1, 2, 3];
  w.add(4); // 可以修改
  w.length = 2; // 可以修改
  print(w); // [1,2]

  q.length = 2; // 允许的操作,直接把数组截断元素也会被消失。
  print('len slice $q'); // 输出:[1, '2']

  var q2 = <int>[123123, 123, 123123];
  print(q2); // 声明集合类型

  // 创建固定长度的集合,不能扩容,也不修改长度,第二个参数为默认填充的值
  var lengthList = List.filled(2, 1);
  // lengthList.add(1); // 报错:不可add 数组长度已经定义好了。
  lengthList[0] = 1;
  // lengthList[1] = '2'; // 报错,开始已经声明了类型,类型不一致;
  print(lengthList);

高级用法

  final list = [];
  list.add(1);
  list.add('12312');
  list.add('456');

  // 新增并返回列表本身(链式操作)
  final lists = list
    ..addAll([1, 2, 3])
    ..add(2);
  print(lists); // 输出:[1, 12312, 456, 1, 2, 3, 2]

  // 删除
  list.remove(1); // 根据值来删除数据
  list.removeAt(0); // 根据索引来删除删除
  list.removeRange(0, 2); // 删除集合的一段位置的数据(根据索引)

  // 扩展运算符
  final list3 = [...list];
  print(list3); // 输出:[1, 12312, 456, 1, 2, 3, 2]

  // 指定位置插入
  list.insert(1, 123);
  list.insertAll(2, [1, 2, 3]);
  print(list); // 输出:[1, 123, 1, 2, 3, 12312, 456, 1, 2, 3, 2]

  // 获取第一个元素
  final firstItem = list.first; // 输出:1

  // 查看数组是不是空
  final isEmpty = list.isEmpty; // 输出:false

  // 排序
  final list2 = ['b21', 'a23'];
  list2.sort(); // 会报错,sort 只能对相同类型的值进行排序,多类型的数组,不能直接排序
  print(list2); // 输出:[a23, b21]

  // 多类型数组排序, 需要预先声明一个排序函数
  int typePriority(dynamic x) {
    if (x is int) return 1; // 数字排第一
    if (x is String) return 2; // 字符串排第二
    if (x is bool) return 3; // 布尔值排第三
    return 4;
  }

  final list4 = [1, true, null, '2'];
  list4.sort((a, b) {
    final aa = typePriority(a);
    final bb = typePriority(b);

    if (aa != bb) {
      return aa.compareTo(bb);
    }
    return 0;
  });
  print(list4); // 输出:[1, 2, true, null]

  list.forEach((item) => {print(item)}); // foreach 遍历

  final doubleItem = list.map((item) => item * 2); // map 遍历 输出: (2, 1231212312)

  final oneFMatch = list.firstWhere(
    (item) => item == 1,
  ); // find 查找,只找第一个 输出:(1)

  final oneLMatch = list.lastWhere(
    (item) => item == 1,
  ); // find 查找,只找最后一个 输出:(1)

  final oneMatch = list.where(
    (item) => item == 1,
  ); // 全量查找,输出:(1) 条件为:item > 1 会报错。因为字符串和整形不可比较

  final allMatch = list.every(
    (item) => item is String,
  ); // 是否数组全部都满足条件,输出: false

  final has_value = list.contains(1); // 查看是否包含一个值,输出:true

  final index = list.indexOf(22); // 和js一样,返回索引不存在则返回-1,输出:-1

  final reduceList = list.reduce((pre, item) => item); // 和 ts一样

  // 累加
  final sum = list.reduce((pre, item) {
    if (item is int && pre is int) {
      return item + pre;
    }
    return pre;
  });
  final sum2 = list.whereType<int>().fold(
    0,
    (pre, next) => pre + next,
  ); // 先将列表中的值提取物出来在累加, fold 可以预先声明一个初始值
  print('$sum, $sum2');

空类型

  // dart 中空类型只有null,没有 undefined
  final w = null;
  print(w); // nll

  // late 表示延后给变量赋值,保证一定会赋值
  late String q;
  // print(q); // 报错,变量还没赋值
  q = '12312';
  print(q);

  var q2 = null;
  String? qq;

  if (q2 == null) { // 不能使用 is
    qq ??= '12312'; // 如果 qq值为空,则给qq赋值
  }
  print(qq);

Map 类型

  // new Map 初始化,和下面的是一样的。
  Map<String, int> aa = {'aa': 12};

  // 这个是 Map 自动类型推导
  final k = {
    'a': 1,
    'b': 2,
    'c': [1, true],
    'w': [],
    'aa': [1, 2, 3],
  };

  k['c'] = 123123; // final 支持随意修改、const 不支持修改
  print(k);

  (k['w'] as List).add('1');  // 必须类型断言
  (k['w'] as List).add(2);
  print(k);

  // 存在浅拷贝的问题
  final q = k['w'] as List;
  q.length = 0;
  print('$q ---- $k');

  // 避免浅拷贝问题
  final q2 = List.from(k['aa'] as Iterable); // 深拷贝赋值
  q2.add('qqqq');
  print('$q2 ---- $k');

  // Map 集合(dynamic 类似于 ts 的 any 类型)
  // 和 final users = [xxx] 一样
  List<Map<String, dynamic>> users = [
    {
      'id': 1,
      'name': 'Alice',
      'tags': ['developer', 'runner'], // 嵌套列表
    },
    {'id': 2, 'name': 'Bob', 'tags': []},
  ];

类型判断

  final users = [];

  // 判断类型,比对类型 is 关键字
  if (users is List) {
    print(1);
  } else {
    print(2);
  }
  // 输出:1

链式操作符


  // 级联操作符:执行操作,但忽略返回值,最终返回对象本身。
  // 不用级联操作符
  var button = Button();
  button.text = 'Confirm';
  button.color = 'Blue';
  button.onClick(() => print('Clicked'));

  // 使用级联操作符,始终获取的是第一步的返回值(第一步的值是动态的)。
  var button =
      Button() // 1. 创建对象(最初的接收者)
        ..text =
            'Confirm' // 2. 在“1”的对象上执行赋值,完成后丢弃返回值,返回“1”
        ..color =
            'Blue' // 3. 在“1”的对象上执行赋值,完成后丢弃返回值,返回“1”
        ..onClick(() => print('...')); // 4. 在“1”的对象上调用方法,完成后丢弃返回值,返回“1”

  // 返回的第一步的值是动态的
  final list = [];
  final newList = list
    ..add(1)
    ..addAll([2, 3, 4]); // 输出:[1,2,3,4],最初list是空数组,最终输出的是最新的数组