Dart基础

一、dart概述

Dart简介

  • Dart 是谷歌开发的,类型安全的,面向对象的编程语言,被应用于Web、服务器、移动应用和物联网等领域。
  • Dart 诞生于 2011 年 10 月 10 日
  • Dart简单易学(类似TypeScript, 是强类型的语言)
  • 运行方式
    • 原生虚拟机(Dart 代码可以运行在 Windows, Mac、 Linux 上)
    • JavaScript 引擎(Dart代码可以转成 JS代码,然后运行在浏览器上)

在这里插入图片描述

dart环境搭建

  • 从flutter 1.21版本开始,flutter SDK会同时包含完整的dart SDK
    在这里插入图片描述
  • 官网介绍:https://dart.cn/get-dart

Dart环境搭建-绑定环境变量

  • 先确定 Flutter SDK 的安装路径
    • 例如:我的 Flutter SDK 安装路径是 D:\flutter
  • D:\flutter\bin
    • Flutter 和 Dart 的相关的执行命令
  • D:\flutter\bin\cache\dart-sdk\bin
    • Dart SDK的相关命令的执行路径
  • D:\flutter. pub-cache\bin
    • Pub 下载的公共模块的执行路径

Dart资源网站

官网
英文 https://dart.dev/
中文 https://dart.cn/
在线运行代码
https://dartpad. dartlang. org
https://dartpad.cn/
生态
https://pub.dev/

二、dart 基础语法

在这里插入图片描述

语法基础

  • 注释语法与 JS 一致
  • 声明函数不需要关键字 (Js 中通过 function 关键字来声明函数)
  • 函数和参数前面都有类型声明,void表示没有返回值,int是整型数
  • 字打印使用 print ( Js 使用 console. log() )
  • 每行代码结束时,必须写结束分号(😉
  • 字符串通过引号包起来,支持模板字符串
  • main 是入口函数, Dart应用程序总是从 main 函数开始执行
  • 用 var 声明的变量,其数据类型是动态的

语法基础-运行

  • 在命令行中运行

    • dart hello.dart
  • Dart 执行文件中的main函数
    在这里插入图片描述

  • 输出Hello,World

语法基础 - 注释

单行注释

// 我是单行注释

·多行注释

/* 我是多行注释*/

文档注释

/// 我是文档注释

可以通过 dartdoc将注释转成文档(文档注释支持 markdown 语法)

语法基础-变量

  • 变量是一个引用,Dart万物皆对象,变量存储的是对象的引用声明变量
    • 明确指定类型: int age = 18;
    • 不明确类型: var age = 18; 或 dynamic age = 18;
  • 变量名大小写敏感(age与 Age是两个不同的变量)
  • 变量默认值是 null (Js 中变量默认值是 undefined)
  • Dart变量的值不会进行隐式转换(null不会自动转成false)

语法基础-常量

  • 常量就是值不可变的变量(一旦声明,其值不能更改)
  • 声明常量
    • const age = 18;
    • final age = 18;
  • const 与 final 的区别
    • const time = DateTime. now(); // 报错 -无法将运行时的值分配给const 变量
    • final time = DateTime.now(); / 成功 - 可以将运行时的值分配给

三、数据类型 Number

  • Dart 中的数字由三个关键字描述
  • num 数字类型(既可以是整数,也可以是小数)
    • int 表示整数(必须是整数)
    • double 表示浮点数(既可以是整数,也可以是小数)
  • 常用API
    • https://api. dart. cn/stable/dart-core/num-class. html
    • https://api. dart. cn/stable/dart-core/int-class. html
    • https://api. dart.cn/stable/dart-core/double-class. html
void main() {
  // 声明整数
  int count = 3;
  print(count);

  // 声明浮点数
  double price = 3.7;
  print(price);

  // 声明数值类型
  num n1 = 3.7;
  print(n1);

  // 类型转换
  print(n1.toString());
  print(3.8.toInt()); // 向下取整

  // 四舍五入
  print(3.1415926.round());
  print(3.1415926.toStringAsFixed(4));

  // 返回余数
  print(10.remainder(4));

  // 数字比较: 0: 相同,1:大于,-1:小于
  print(10.compareTo(12));
  // 返回最大公约数
  print(12.gcd(18));

  // 科学计数法
  print(1000.toStringAsExponential(1));
}

四、Dart 数据类型 - String

  • 声明字符串 (String)
    • 单引号、双引号都可以
    • 三个引号可以声明包含换行符的字符串
  • 常见API
    • https://api dart.cn/stable/dart-core/String-class. html
  • 正则表达式
    • RegExp (r’正则表达式’)
    • RegExp (r’\d+')
void main() {
  // 声明字符串
  // var str1 = 'Hello, World'; // 单引号
  // print(str1);
  // var str2 = "你好,世界"; // 双引号
  // print(str2);

  String str1 = 'Hello, World'; // 单引号
  print(str1);
  String str2 = "你好,世界"; // 双引号
  print(str2);

  // 通过三个引号声明字符串
  String str3 = '''Hello
  World
  ''';
  print(str3);

  // 常见操作
  // 字符串拼接
  print(str1 + str2);
  print("$str1 $str2");

  // 字符串的分隔
  print(str1.split(''));

  // 字符串的裁切
  print('  abc   '.trim());

  // 判断字符串是否为空
  print(''.isEmpty);
  print(''.isNotEmpty);

  // 字符串替换
  print(str1.replaceAll('World', 'Dart'));
  // 支持正则替换
  print('h1k2d3n4n5n'.replaceAll(RegExp(r'\d+'), '_'));

  // 通过正则匹配手机号
  var isPhone = RegExp(r'^1\d{10}$');
  print(isPhone.hasMatch('13333333333'));
  print(isPhone.hasMatch('1333333333'));

  // 查找字符串
  print(str1.contains('e'));
  // 定位字符串
  print(str1.indexOf('e'));
}

五、数据类型-boolean

void main() {
  // 声明布尔类型
  bool flag1 = true;
  print(flag1);

  bool flag2 = false;
  print(flag2);

  // 显式地进行判断
  var flag3;
  if (flag3 == null) {
    print('真');
  } else {
    print('假');
  }

  // 一些特殊的判断场景
  var n1 = 0 / 0;
  print(n1);
  print(n1.isNaN);
}

六、数据类型-list

  • Dart中的数组,由List对象表示。List有两种声明方式
    • 字面量方式
      • List list = []; // 不限定元素的数据类型
      • List list = []; // 限定元素的数据类型是 int
  • 构造函数方式
    • List list = new List. empty(growable: true); // 不限制长度的空列
    • List list = new List.filled(3, 0); // 声明指定长度的填充列表
  • 扩展操作符(…)
    • var list = [1, 2, 3];
    • var list2 = [0, …list]; // [0, 1, 2, 3]
  • 常用AP
    • Ihttps://api. dart. cn/stable/dart-core/List-class. html
void main() {
  // 声明List - 字面量
  List l1 = ['a', 'b', 'c', 1, 2, 3];
  print(l1);

  List l2 = <int>[1, 2, 3]; // 限定元素类型的声明方式
  print(l2);

  // 通过构造函数的声明方式
  var l3 = new List.empty(growable: true);
  l3.add(1);
  print(l3);

  var l4 = new List.filled(3, 6);
  print(l4);

  // 扩展操作符
  var l5 = [0, ...l4];
  print(l5);

  var l6;
  var l7 = [7, ...?l6];
  print(l7);

  // 返回列表的长度
  print(l1.length);

  // 列表的反转
  print(l1.reversed.toList());

  // 添加元素
  l3.addAll([4,5,6]);
  print(l3);

  // 删除元素
  l3.remove(6);
  print(l3);
  // 根据下标删除元素
  l3.removeAt(1);
  print(l3);

  // 在指定的位置添加元素
  l3.insert(1, 9);
  print(l3);

  // 清空
  l3.clear();
  print(l3.length);
  print(l3.isEmpty);

  // 合并元素
  List words = ['Hello', 'World'];
  print(words.join('-'));
}

七、Dart数据类型 遍历List

  • forEach 遍历列表
  • map 遍历并处理元素,然后生成新的列表
  • where () 返回满足条件的数据
  • any 只要有一项满足条件,即返回 true
  • every () 判断是否每一项都满足条件,都满足条件才返回 true
void main() {
  var nums = [1, 2, 3];

  // for 循环进行遍历
  for (var i = 0; i < nums.length; i++) {
    print(nums[i]);
  }

  // for ... in
  for (var item in nums) {
    print(item);
  }

  // forEach
  nums.forEach((element) {
    print(element);
  });

  // var newNums = [];
  // for (var i = 0; i < nums.length; i++) {
  //   newNums.add(nums[i] * nums[i]);
  // }
  // print(newNums);

  // map 循环之后会得到一个处理后的列表
  var newNums = nums.map((e) {
    return e * e;
  });
  print(newNums.toList());

  // where() 返回符合条件的元素
  // 判断数字是否是奇数
  bool isOdd(n) => n % 2 == 1;
  var oddNum = nums.where((element) => isOdd(element));
  print(oddNum.toList());

  // 使用 any() 来检测是否有奇数(至少一个)
  print(nums.any(isOdd));

  // 使用 every() 来判断是否都是奇数
  print(nums.every(isOdd));

  // 扩展
  var pairs = [[1, 2], [3, 4]];
  var flattened = pairs.expand((element) => element).toList();
  print(flattened); // [1, 2, 3, 4]

  // 折叠 - 对列表中的每一个元素,做一个累计操作
  int result = nums.fold(2, (p, element) => p * element); // 2 * (1*2*3)
  print(result);
}

八、数据类型-set

  • Set 是一个无序的,元素唯一的集合
  • Set有字面量和构造函数两种声明方式(字面量中用大括号)
  • 无法通过下标取值
  • 具有集合特有的操作
    • 例如:求交集,并集、差集等
  • 常用API
    • https://api. dart. cn/stable/dart-core/Set-class. html
void main() {
  // 字面量
  var nums = <int>{1, 2, 3};
  print(nums);

  // 构造函数
  var fruits = new Set();
  fruits.add('香蕉');
  fruits.add('苹果');
  fruits.add('橘子');
  print(fruits);
  print(fruits.toList());

  List myNums = [1, 2, 3, 3, 4];
  print(myNums.toSet()); // 可以将重复的元素过滤掉

  // 集合特有的操作
  var caocao = new Set();
  caocao.addAll(['张辽', '司马懿', '关羽']);

  var liubei = new Set();
  liubei.addAll(['关羽', '张飞', '诸葛亮']);

  // 求交集
  print(caocao.intersection(liubei));

  // 求并集
  print(caocao.union(liubei));

  // 求差集
  print(caocao.difference(liubei));

  // 返回第一个元素
  print(caocao.first);
  // 返回最后一个
  print(caocao.last);

  // 集合不能通过下标取值
  // print(caocao[1]);
}

九、Dart 数据类型 - Map

  • Map是一个无序的键值对(key-value)映射。通常被称作哈希或字典。
  • 声明方式
    • var map key1: value1, key2: value2};
    • var map = new Map () ;
    • map[‘key’] = value;
  • 常用API
    • https://api. dart.cn/stable/dart-core/Map-class. htm
void main() {
  // 字面量
  var person = {
    'name': '张三', 
    'age': 20
  };
  print(person);

  // 构造函数
  var p = Map();
  p['name'] = '李四';
  p['age'] = 22;
  print(p);

  // 访问属性
  print(p['name']);

  // 判断 Map 中的 key 是否存在
  print(p.containsKey('name'));
  print(p.containsKey('aaa'));

  // 赋值
  // 如果 key 不存在,我们才赋值(如果key已经存在,则不赋值)
  p.putIfAbsent('gender', () => '男');
  print(p);
  p.putIfAbsent('gender', () => '女');
  print(p);

  // 获取 Map 中所有的 key
  print(p.keys);
  // 获取 Map 中所有的 value
  print(p.values);

  // 根据条件进行删除
  p.removeWhere((key, value) => key == 'gender');
  print(p);
}

十、Dart数据类型 - 其他

  • Runes (符文)
    • Runes 对象是一个32位字符对象。它可以把文字转换成符号表情或特定的文字
    • print(‘\u{1f44d}’) =>
    • https://copychar.cc/
  • Symbol
    • 在Dart 中符号用 #开头来表示的标识符
  • dynamic
    • 动态数据类型
void main() {
  var str = '😀';
  print(str);
  print(str.length); // UTF-16
  print(str.runes.length); // UTF-32

  // Runes 可以将 UTF-32 字符集表示的内容转成符号
  Runes input = new Runes('\u{1f680}');
  print(new String.fromCharCodes(input));

  // Symbol
  var a = #abc;
  print(a);
  var b = new Symbol('abc');
  print(b);

  print(#abc == new Symbol('abc'));

  // 声明动态类型的变量
  dynamic foo = 'bar';
  foo = 123;
  print(foo);
}

十一、Dart运算符

  • 地板除(~/)
  • 类型判断运算符(is | is!)
  • 避空运算符(?? | ??=)
  • 条件属性访问(?.)
  • 级联运算符(.)
    • myObject. myMethod () ; // 返回 myMethod 的返回
    • myObject.myMethod (); // 返回 myObject 对象的引用
void main() {
  // 地板除
  print(7 ~/ 4);

  // 类型判断运算符
  List list = [];
  if (list is List) {
    print('list is List');
  } else {
    print('list is not List');
  }

  if (list is! List) {
    print('不是列表');
  } else {
    print('是列表');
  }

  // 避空运算符
  print(1 ?? 3); // 返回 1
  print(null ?? 12); // 返回 12

  var foo;
  // foo = 6;
  print(foo ?? 0); // 如果 foo 是 null,则返回 0

  var a;
  // if (a == null) {
  //   a = 3;
  // }
  a ??= 3;
  print(a);
  a ??= 6; // 如果 a 不是 null。则赋值失败
  print(a);

  // 条件属性运算符(保护可能为空的属性)
  var m = new Map();
  print(m.length);
  var obj;
  // print(obj.length); // The getter 'length' was called on null.
  print(obj?.length);

  // 级联运算符
  // Set s = new Set();
  // s.add(1);
  // s.add(2);
  // s.add(3);
  // s.remove(2);
  // print(s);

  Set s = new Set();
  s..add('a')..add('b')
   ..add('c')
   ..remove('b');
  print(s);
}

十二、Dart函数-声明函数

  • 直接声明
    • Dart 中声明函数不需要 function 关键字
  • 箭头函数
    • Dart中的箭头函数中,函数体只能写一行且不能带有结束的分
    • Dart 中的箭头函数,只是函数的一种简写形式
  • 匿名函数
  • 立即执行函数
// Dart 中声明函数,不需要 function 关键字
void printInfo() {
  print('Hello, World');
}

// 返回值,与函数声明的类型要一致
int getNum() {
  // return 'Hello'; // 不能返回字符串类型
  return 1;
}

void main() {
  // 调用函数
  printInfo();

  print(getNum());

  // 匿名函数
  var myPrint = (value) {
    print(value);
  };
  List fruits = ['苹果', '香蕉', '猕猴桃'];
  fruits.forEach(myPrint);

  // 箭头函数
  fruits.forEach((element) => { 
    print(element) // 箭头函数中,不能写结束的分号(;)
  });
  fruits.forEach((element) => print(element));

  // 立即执行函数
  ((int n){
    print(n);
  }) (17);
}

十三、Dart函数- 函数参数

  • 必填参数
    • 参数类型 参数名称
  • 可选参数
    • 放在必选参数后面
    • 通过中括号包裹起来
    • 带默认值的可选参数
  • 命名参数
    • 用大括号包裹起来
    • 调用函数时,命名参数的名称与声明函数中的名称保持一致
  • 函数参数
void main() {
  // 必填参数
  // String userInfo(String name) {
  //   return '你好:$name';
  // }
  // String res = userInfo('张三');

  // 可选参数
  // String userInfo(String name, [int age = 0]) {
  //   return '你好:$name, 年龄:$age';
  // }

  // String res = userInfo('张三', 20);
  // print(res);

  // 命名参数
  String userInfo(String name, {int age = 0}) {
    return '你好:$name, 年龄:$age';
  }

  // 命名参数调用时,需要与声明时的形参一致
  String res = userInfo('张三', age: 20);
  print(res);

  // 函数参数
  var myPrint = (value) {
    print(value);
  };
  List fruits = ['苹果', '香蕉', '猕猴桃'];
  // 将匿名函数 myPrint 传递给函数 forEach
  fruits.forEach(myPrint);
}

十四、Dart 函数 - 作用域

在这里插入图片描述

  • Dart 中闭包的实现方式与 JavaScript 中完全一致
  • 使用时机:即能重用变量,又保护变量不被污染
  • 实现原理:外层函数被调用后,外层函数的作用域对象(A0)被内层函数引用着,导致外层函数的作用域对象无法释放,从而形成闭包
// 全局变量
var globalNum = 100;

void main() {
  printInfo() {
    // 局部变量
    var localNum = 10;
    localNum--;
    print(localNum);
    print(globalNum); // 我们可以在函数作用域中,访问全局变量
  }

  printInfo();
  // print(localNum); // 不能在全局作用域中,访问局部变量

  // 闭包
  printInfo();
  printInfo();

  parent() {
    var money = 1000;
    return () {
      money -= 100;
      print(money);
    };
  }

  var p = parent();
  p();
  p();
  p();
}

十五、Dart 函数- 异步函数

  • JavaScript 中,异步调用通过Promise来实现
    • async 函数返回一个 Promise。 await 用于等待 Promise
  • Dart 中,异步调用通过 Future 来实现
    • async 函数返回一个 Future, await 用于等待 Future
  • Future详情
    • https://api. dart. dev/stable/dart-async/Future-class. html
import 'package:http/http.dart' as http; // http请求包
import 'dart:convert'; // 解析json包

// https://httpbin.org/ip 返回 IP 地址
Future getIPAddress() {
  final url = 'https://httpbin.org/ip';
  return http.get(url).then((response) {
    // print(response.body);
    String ip = jsonDecode(response.body)['origin'];
    return ip;
  });
}

void main() {
  // 调用 getIPAddress
  getIPAddress()
    .then((ip) => print(ip))
    .catchError((error) => print(error));
}

async

import 'package:http/http.dart' as http;
import 'dart:convert';

// https://httpbin.org/ip 返回 IP 地址
Future getIPAddress() async {
  final url = 'https://httpbin.org/ip';
  final response = await http.get(url);
  String ip = jsonDecode(response.body)['origin'];
  return ip;
}

void main() async {
  // 调用 getIPAddress
  try {
    final ip = await getIPAddress();
    print(ip);
  } catch (error) {
    print(error);
  }
}

十六、类-简介

  • 类是通过 class 声明的代码段,包含属性和方法。
  • 属性:用来描述类的变量
  • 方法:类中的函数称为类的方法
  • 对象是类的实例化结果 (var obj = new MyClass())
    在这里插入图片描述
  • 类是通过class 声明的代码段,包含属性和方法。
    • 属性:用来描述类的变量
    • 方法:类中的函数称为类的方法
  • 对象是类的实例化结果(var obj = new MyClass ())
  • 编程方式
    • 面向对象编程(00P)
    • 面向过程编程(POP)
// 声明类
class Person {
  // 类的属性
  String name = '张三';

  // 类的方法
  void getInfo() {
    print('我是 $name');
  }
}

void main() {
  // 实例化类,然后得到一个对象
  Person p = new Person();
  // 访问类中的属性
  print(p.name);

  // 访问类的方法
  p.getInfo();

  // Dart 中所有的内容都是对象
  Map m = new Map();
  print(m.length);
  m.addAll({'name': '李四', 'age': 20});
  print(m.length);
}

十七、构造器(构造函数)

  • 默认构造函数
    • 与类同名的函数,在实例化时,自动被调用
  • 命名构造函数
    • 在类中使用命名构造器(类名.函数名)实现多个构造器,可以提供额外的清晰度
  • 常量构造函数
    • 如果类生成的对象不会改变,您可以通过常量构造函数使这些对象成为编译时常量
  • 工厂构造函数
    • 通过factory声明,工厂函数不会自动生成实例,而是通过代码来决定返回的实例

默认构造函数

// class Point {
//   // num x;
//   // num y;
//   num x, y;

//   // 声明普通构造函数
//   Point() {
//     print('我是默认构造函数,实例化时,会第一个被调用');

//     // this 可以省略
//     // x = 0;
//     // y = 0;

//     // 当命名指向有歧义时,this 不能省略
//     this.x = 0;
//     this.y = 0;
//   }
// }

// class Point {
//   num x, y;

//   // 声明普通构造函数
//   Point(num x, num y) {
//     // 当命名指向有歧义时,this 不能省略
//     this.x = x;
//     this.y = y;
//   }
// }

class Point {
  num x, y;

  // 声明普通构造函数
  Point(this.x, this.y);
}

void main() {
  // var p = new Point();
  // print(p.x);

  var p = new Point(3, 4);
  print(p.y);
}

命名构造函数

class Point {
  num x, y;

  Point(this.x, this.y);

  // 命名构造函数
  Point.origin() {
    x = 0;
    y = 0;
  }

  // 命名构造函数
  Point.fromJson({x: 0, y: 0}) {
    this.x = x;
    this.y = y;
  }
}

void main() {
  // 默认坐标
  Point p1 = new Point.origin();
  print(p1.x);

  // 手动设置坐标
  Point p2 = new Point.fromJson(x: 6, y: 6);
  print(p2.x);
}

常量构造函数

class Point {
  num x;
  num y;

  Point(this.x, this.y);
}

class ImmutablePoint {
  // 属性必须通过 final 声明
  final num x;
  final num y;

  // 常量构造函数,必须通过 const 声明
  const ImmutablePoint(this.x, this.y);
}

void main() {
  var p1 = new Point(1, 2);
  var p2 = new Point(1, 2);
  print(p1 == p2); // false

  // 常量构造函数,可以当做普通构造函数使用。
  // var p3 = new ImmutablePoint(1, 2);
  // var p4 = new ImmutablePoint(1, 2);
  // print(p3 == p4); // false

  // // 声明不可变对象,必须通过 const 关键字
  // var p5 = const ImmutablePoint(1, 2);
  // var p6 = const ImmutablePoint(1, 2);
  // print(p5 == p6); // true

  // // 实例化时,new 关键字,可以省略。
  // var p7 = ImmutablePoint(1, 2);
  // var p8 = ImmutablePoint(1, 2);
  // print(p7 == p8); // false
}

工厂构造函数 也是单例模式

class Person {
  String name;

  static Person instance;

  // 工厂构造函数
  factory Person([String name = '刘备']) {
    // 工厂构造函数中,不能使用 this 关键字
    // print(this.name);
    if (Person.instance == null) {
      // 第一次实例化
      Person.instance = new Person.newSelf(name);
    }
    // 非第一次实例化
    return Person.instance;
  }

  // 命名构造函数
  Person.newSelf(this.name);
}

void main() {
  // 实例化操作
  Person p1 = new Person('关羽');
  print(p1.name);

  Person p2 = new Person('张飞');
  print(p2.name);

  print(p1 == p2); // true
}

十八、访问修饰

  • Dart 与TypeScript不同,没有访问修饰符(public、protected, private)
  • Dart类中,默认的访问修饰符是公开的(即 public)
  • 如果属性或方法以 _ (下划线)开头,则表示私有(即 private)
  • 只有把类单独抽离出去,私有属性和方法才起作用
    • lib/Person. dart
    • import ‘lib/Person. dart’

lib/Person. dart

class Person {
  String name;

  // 声明私有属性
  num _money = 100;

  Person(this.name);

  num getMoney() {
    return this._money;
  }

  // 声明私有方法
  void _wife() {
    print('我是 $name 的老婆');
  }
}

外面引入调用

import 'lib/Person.dart';

void main() {
  var p = new Person('张三');
  print(p.name);

  // 访问私有属性
  // print(p._money);

  print(p.getMoney());

  // 访问私有方法
  // print(p._wife());
}

十九、Getter Setter

  • Getter (获取器)是通过 get关键字修饰的方法
    • 函数没有小括号,访问时也没有小括号(像访问属性一样访问方法)
  • Setter (修改器)是通过 set关键字修饰的方法
    • 访问时,像设置属性一样给函数传参
class Circle {
  final double PI = 3.1415;
  num r;

  Circle(this.r);

  // num area() {
  //   return this.PI * this.r * this.r;
  // }

  // 使用 get 声明的方法,不能有小括号
  num get area {
    return this.PI * this.r * this.r;
  }

  // Setter
  set setR(value) {
    this.r = value;
  }
}

void main() {
  var c = new Circle(10);
  // print(c.area());

  // 通过 Setter 修改属性
  c.setR = 20;

  print(c.area);
}

二十、初始化列表

在这里插入图片描述

class Rect {
  int height;
  int width;

  // Rect(this.height, this.width);

  // Rect([int height = 2, int width = 10]) {
  //   this.height = height;
  //   this.width = width;
  //   print('${this.height} -- ${this.width}');
  // }

  // Rect({int height = 2, int width = 10}) {
  //   this.height = height;
  //   this.width = width;
  //   print('${this.height} -- ${this.width}');
  // }

  // 初始化列表
  Rect() : height = 4, width = 20 {
    print('${this.height} -- ${this.width}');
  }
}

class Point {
  double x, y, z;

  Point(this.x, this.y, this.z);

  // 初始化列表的特殊用法(重定向构造函数)
  Point.twoD(double x, double y) : this(x, y, 0);
}

void main() {
  var r = new Rect();

  // 实例化点
  var p = new Point(1,2,3);
  print(p.z);

  var p2 = new Point.twoD(4, 5);
  print(p2.z);
}

二十一、static

  • static关键字用来指定静态成员
    • 通过 static 修饰的属性是静态属性
    • 通过 static 修饰的方法是静态方法
  • 静态成员可以通过类名称直接访问(不需要实例化)
    • 实例化是比较消耗资源的,声明静态成员,可以提高程序性能
  • 静态方法不能访问非静态成员,非静态方法可以访问静态成员
    • 静态方法中不能使用 this 关键字
    • 不能使用 this 关键字,访问静态属性
class Person {
  static String name = '张三';
  int age = 18;

  static printInfo() {
    // print(this.name); // 不能通过 this 关键字,访问静态属性
    print(name);

    // 静态方法中不能访问非静态属性
    // print(age);

    // 静态方法,不能访问非静态方法
    // printUserInfo();
  }

  printUserInfo() {
    // 非静态方法,可以访问静态属性
    print(name);
    print(age);

    printInfo(); // 非静态方法,可以访问静态方法
  }
}

void main() {
  // 静态成员,可以通过类名称直接访问
  print(Person.name);
  print(Person.printInfo());

  // 不能通过类名称,直接访问非静态方法。
  // print(Person.printUserInfo());

  var p = new Person();
  // print(p.name); // 不能通过实例化对象去访问静态属性
  print(p.printUserInfo());
}

二十二、元数据

  • 元数据以 @ 开头,可以给代码标记一些额外的信息
    • 元数据可以用来库,类,构造器,函数,字段,参数或变量声明的前
  • @override (重写)
    • 某方法添加该注解后,表示重写了父类中的同名方法
  • @required (必填)
    • 可以通过 @required 来注解 Dart 中的命名参数,用来指示它是必填参
  • @deprecated (弃用)
    • 若某类或某方法加上该注解之后,表示此方法或类不再建议使用
class Phone {
  // 这是旧版本中的开机方法,会在将来的版本中移除
  
  activate() {
    turnOn();
  }

  turnOn() {
    print('开机');
  }
}

void main() {
  var p = new Phone();
  p.activate();

  p.turnOn();
}

二十三、Dart类与对象 - 继承

  • 根据类的先后顺序,可以将类分成父类和子类
  • 子类通过 extends 关键字 继承 父类
    • 继承后,子类可以使用父类中,可见的内容(属性或方法)
  • 子类中,可以通过 @override 元数据来标记“覆写”方法
    • “覆写”方法:子类中与父类中同名的方法
  • 子类中,可以通过 super 关键字来引用父类中,可见的内容
    • 属性
    • 方法(普通构造函数,命名构造函数)

lib/father.dart

class Father {
  String name = '刘备';
  num _money = 10000;
  String job;

  Father(this.job);

  // 命名构造函数
  Father.origin(this.job);

  say() {
    print('我是 $name');
  }

  get getMoney {
    return this._money;
  }
}

lib/son.dart

import 'Father.dart';

class Son extends Father {
  String name = "刘禅";

  // 通过 super 继承父类的普通构造函数
  Son(String job) : super(job);

  // 继承命名构造函数
  // Son(String job) : super.origin(job);
  Son.origin(String job) : super.origin(job);

  
  say() {
    super.say();
    print('我是 刘禅, 我爹是 ${super.name},他的工作${super.job}');
  }
}
import 'lib/Father.dart';
import 'lib/Son.dart';

void main() {
  var f = new Father('皇帝');
  print(f.name);


  // var s = new Son('皇帝');
  var s = new Son.origin('卖草鞋的');
  print(s.name);
  // print(s._money); // 子类不能访问父类中的私有内容
  print(s.getMoney);
  s.say();
}

二十四、Dart类与对象- 抽象类

  • 抽象类是用 abstract 关键字修饰的类
  • 抽象类的作用是充当普通类的模板,约定一些必要的属性和方法
  • 抽象方法是指没有方法体的方法
    • 抽象类中一般都有抽象方法,也可以没有抽象方法
    • 普通类中,不能有抽象方法
  • 抽象类不能被实例化(不能被 new)
  • 抽象类可以被普通类继承(extends)
    • 如果普通类继承抽象类,必须实现抽象类中所有的抽象方法
  • 抽象类还可以充当接口被实现(implements)
    • 如果把抽象类当做接口实现的话,普通类必须得实现抽象类里面定义的所有属性和方法。
// 1. 抽象类,必须通过 abstract 关键字声明
// 2. 抽象类中,可以有抽象方法,也可以没有抽象方法,一般来说,抽象类都有抽象方法。
abstract class Phone {
  // 声明抽象方法
  void processor(); // 手机的处理器

  void camera(); // 手机的摄像头

  void info() {
    print('我是抽象类中的一个普通方法');
  }
}

class Xiaomi extends Phone {
  // 普通类继承了抽象类,就必须实现抽象类中所有的抽象方法
  
  void processor() {
    print('骁龙888');
  }

  
  void camera() {
    print('三星摄像头');
  }

  // 普通类中,不能有抽象方法
  // void aaa();
}

class Huawei extends Phone {
  // 普通类继承了抽象类,就必须实现抽象类中所有的抽象方法
  
  void processor() {
    print('麒麟990');
  }

  
  void camera() {
    print('徕卡摄像头');
  }
}

void main() {
  // 抽象类,不能被实例化
  // var p1 = new Phone();

  Xiaomi m = new Xiaomi();
  m.processor();
  m.camera();
  m.info();

  Huawei h = new Huawei();
  h.processor();
  h.camera();
  h.info();
}

二十五、Dart类与对象-接口

  • 接口在Dart 中就是一个类(只是用法不同)
    • 与 Java 不同, Java 中的接口需要用 interface 关键字声明; Dart 中不需要
    • 接口可以是任意类,但一般使用抽象类做接口
  • 一个类可以实现(implements)多个接口,多个接口用逗号分隔
    • class MyClass implements Interface1, Interface2 . )
    • 接口可以看成一个个小零件。类实现接口就相当于组装零件
  • 普通类实现接口后,必须重写接口中所有的属性和方法
// 手机的处理器
abstract class Processor {
  String cores; // 内核:2核,4核
  arch(String name); // 芯片制程:7nm, 5nm
}

// 手机的摄像头
abstract class Camera {
  String resolution; // 分辨率:1000万,3000万
  brand(String name); // 品牌:三星,徕卡,蔡司
}

// 通过普通类实现接口
class Phone implements Processor, Camera {
  
  String cores;

  
  String resolution;

  Phone(this.cores, this.resolution);

  
  arch(String name) {
    print('芯片制程:'+name);
  }

  
  brand(String name) {
    print('相机品牌:'+name);
  }
}

void main() {
  Phone p = new Phone('4核', '3000万');
  p.arch('5nm');
  p.brand('徕卡');
}

二十六、Dart类与对象 - 混入 (Mixin)

  • 混入(Mixin)是一段公共代码。混入有两种声明方式:
    • 将类当作混入 class MixinA { … }
      • 作为 Mixin 的类只能继承自 Object,不能继承其他类
      • 作为Mixin 的类不能有构造函数
    • 使用 mixin 关键字声明 mixin MixinB { . }
  • 混入(Mixin)可以提高代码复用的效率,普通类可以通过with来使用混入
    • class MyClass with MixinA, MixinB { . }
  • 使用多个混入时,后引入的混入会覆盖之前混入中的重复的内容
    • MixinA 和 MixinB 中都有 hellb()'方法, Myelass 会使用 MixinB 中的
class Father {

}

// class MixinA extends Father { // 用作混入的类,不能继承除了 Object 以外的其他类
// class MixinA extends Object {
class MixinA {
  String name = 'MixinA';

  // MixinA(); // 用作混入的类,不能拥有构造函数

  void printA() {
    print('A');
  }

  void run() {
    print('A is running');
  }
}

mixin MixinB {
  String name = 'MixinB';

  void printB() {
    print('B');
  }

  void run() {
    print('B is running');
  }
}

class MyClass with MixinA, MixinB {

}

void main() {
  var c = new MyClass();
  c.printA();
  c.printB();

  // 后引入的混入,会覆盖之前引入的混入中重复的内容
  print(c.name);
  c.run();
}

二十七、泛型

  • 泛型是在函数、类、接口中指定宽 数据类 的语法
    • 泛型函数
    • 泛型类
    • 泛型接口
  • 通常,在尖括号中,使用一个字母来代表类型, 例如 E,T,S,K,和这回簧型 函数名<输入类型>(参数类型 参数)
  • 作用:使用泛型可以减少重复的代码,
// String getData(String value) {
//   return value;
// }

// int getData(int value) {
//   return value;
// }

// 不指定数据类型的函数
// getData(value) {
//   return value;
// }

// 泛型函数
// T getData<T>(T value) {
//   return value;
// }

// 只约定参数类型,不约定函数返回值的类型
getData<T>(T value) {
  return value;
}

void main() {
  // print(getData('Hello'));
  // print(getData(10));

  // 调用泛型函数
  print(getData<int>(20));

  print(getData<String>('Hello'));
}
class CommonClass {
  Set s = new Set<int>();

  void add(int value) {
    this.s.add(value);
  }

  void info() {
    print(this.s);
  }
}

// 泛型类
class GenericsClass<T> {
  Set s = new Set<T>();

  void add(T value) {
    this.s.add(value);
  }

  void info() {
    print(this.s);
  }
}

void main() {
  CommonClass c = new CommonClass();
  c.add(1);
  c.add(2);
  c.info();

  // 实例化泛型类
  GenericsClass g = new GenericsClass<int>();
  g.add(1);
  g.add(2);
  g.info();

  GenericsClass g1 = new GenericsClass<String>();
  g1.add('Hello');
  g1.add('World');
  g1.info();

  // Set s = new Set();
  // s.add(1);
  // s.add('hello');
  // print(s);

  // Set s = new Set<int>();
  // s.add(1);
  // // s.add('hello'); // 报错
  // s.add(3);
  // print(s);

  // 字面量形式的泛型
  Set s = <int>{};
  s.add(1);
  // s.add('hello'); // 报错
  s.add(3);
  print(s);
}
abstract class ObjectCache {
  getBykey(String key);
  void setByKey(String key, Object value);
}

abstract class StringCache {
  getBykey(String key);
  void setByKey(String key, String value);
}

// 泛型接口
abstract class Cache<T> {
  getBykey(String key);
  void setByKey(String key, T value);
}

// 文件缓存
class FileCache<T> implements Cache<T> {
  
  getBykey(String key) {
    return null;
  }

  
  void setByKey(String key, T value) {
    print('文件缓存: key=${key} value=${value}');
  }
}

// 内存缓存
class MemoryCache<T> implements Cache<T> {
  
  getBykey(String key) {
    return null;
  }

  
  void setByKey(String key, T value) {
    print('内存缓存: key=${key} value=${value}');
  }
}

void main() {
  // 文件缓存 - 缓存字符串
  // FileCache fc = new FileCache<String>();
  // fc.setByKey('foo', 'bar');
  // fc.setByKey('f', 2); // 报错

  // 文件缓存 - 缓存 Map
  FileCache fc = new FileCache<Map>();
  fc.setByKey('index', {"name": "张三丰", "age": 218});

  // 内存缓存 - 缓存字符串
  // MemoryCache mc = new MemoryCache<String>();
  // mc.setByKey('foo', 'bar');

  // 内存缓存 - 缓存集合
  MemoryCache mc = new MemoryCache<Set>();
  mc.setByKey('home', {1,2,3});
}

范型类型限制

class SomeBaseClass {
  // ...
}

class Foo<T extends SomeBaseClass> {
  String toString() => "Instance of 'Foo<$T>'";
}

// 子类
class Extender extends SomeBaseClass {

}

class AnotherClass {
  // ...
}

void main() {
  var someBaseClassFoo = Foo<SomeBaseClass>();
  print(someBaseClassFoo);

  var extenderFoo = Foo<Extender>();
  print(extenderFoo);

  var foo = Foo();
  print(foo);

  // var f = Foo<AnotherClass>(); // 类型不对,报错
  // print(f);
}

二十八、枚举

  • 枚举是数量固定的常量值,通过enum关键字声明
    • enum Color fred, green, blue}
  • 枚举的 values 常量, 可以获取所有枚举值列表
    • Listcolors = Color. values;
  • 可以通过 index 获取值的索引
    • assert (Color. green. index == 1);
enum Color { red, green, blue}

void main() {
  // 通过 index 返回枚举中具体常量的值
  print(Color.green.index);

  // 通过 values 返回常量列表
  print(Color.values);
  List<Color> colors = Color.values;
  print(colors);

  // 通过下标,访问列表中的内容
  print(colors[0]);
  // 通过 forEach 去遍历列表的内容
  colors.forEach((element) { 
    print('value: $element, index: ${element.index}');
  });
}

二十九、Dart 库与生态

  • Dart 中的库就是具有特定功能的模块
    • 可能包含单个文件,也可能包含多个文件。
  • 按照库的作者进行划分,库可以分成三类
    • 自定义库(工程师自己写的)
    • 系统库(Dart 中自带的)
    • 第三方库(Dart 生态中的)
  • Dart 生态
    • https://pub. dev/
    • pub命令 (D:\flutter\bin\cache\dart-sdk\bin)
      在这里插入图片描述

三十、Dart库与生态

1.通过 library 来声明库
2.通过 import 来引入库
3.通过 part 和 part of 来组装库

自定义库通过libarary来声明库
在这里插入图片描述

自定义库-通过import来引入库
  • 不同类型的库,引入方式不同
    • 自定义库(import ‘库的位置/库名称.dart’)
    • 系统库(import ‘dart:库名称’)
    • 第三方库(后面单独讲)
  • 引入部分库(仅引入需要的内容)
    • 包含引入(show)
    • 排除引入(hide)
  • 指定库的前缀
    • 当库名冲突时,可以通过 as 关键字,给库声明一个前缀
  • 延迟引入(懒加载)
    • 使用 deferred as 关键字来标识需要延时加载的库

自定义库 lib/MyCustom.dart

// library MyCustom;
library my_custom; // 建议写成小写字母+下划线的形式

class MyCustom {
  String name = "MyCustom";
  static num version = 1.0;

  void info() {
    print('我是自定义库');
  }
}
import 'lib/MyCustom.dart';

void main() {
  MyCustom mc = new MyCustom();

  mc.info();
  print(MyCustom.version);
}

三十一、系统库的引入

import 'dart:math';
// import 'dart:core'; // core 库会被默认引入

void main() {
  print(pi);

  print(min(3,6));
  print(max(3,6));
}
引入部分库

lib/common.dart

void f1() {
  print('f1 is running');
}

void f2() {
  print('f2 is running');
}

void f3() {
  print('f3 is running');
}

show.dart

// show 后面指定包含引入的内容
import 'lib/common.dart' show f1, f3;

void main() {
  f1();

  // f2();

  f3();
}

hide.dart

// hide 会隐藏后面的内容
import 'lib/common.dart' hide f1, f3;

void main() {
  // f1();

  f2();

  // f3();
}
引入名字冲突问题
import 'lib/common.dart';
import 'lib/function.dart' as func; // 给库添加前缀,解决命名冲突问题

void main() {
  f1();

  func.f1();
}
异步引入
import 'lib/function.dart' deferred as func;

void main() {
  // func.hello();

  print('1');
  greet();
  print('2');
  print('3');
}

Future greet() async {// Future 表示异步
  await func.loadLibrary();
  func.hello();
}

三十二、part 与 part of

在这里插入图片描述
Camera.dart

// 与主库建立联系
part of phone;

class Camera {
  String name = "摄像头";

  void info() {
    print('我是摄像头');
  }
}

Processor.dart

// 与主库建立联系
part of phone;

class Processor {
  String name = "处理器";

  void info() {
    print('我是处理器');
  }
}

main.dart

library phone;

import 'dart:math';

// 与分库建立联系
part 'Camera.dart';
part 'Processor.dart';

void main() {
  Camera c = new Camera();
  c.info();

  Processor p = new Processor();
  p.info();

  print(pi);
}

使用
_part.dart

import 'lib/phone/main.dart' as phone;

void main() {
  phone.main();
}

三十三、系统库

  • 系统库(也叫核心库)是Dart提供的常用内置库
    • 不需要单独下载,就可以直接使用
  • 引入
    • import ‘dart:库名’;
    • import ‘dart:core’; //会自动引入(无需手动引入)
  • 系统库列表
    • https://dart.cn/guides/libraries
// import 'dart:core'; // 自动引入

void main() {
  // 创建当前时间
  var now = new DateTime.now();
  print(now);

  // 通过普通构造函数创建时间
  var d = new DateTime(2021, 1, 20, 9, 30);
  print(d);

  // 创建标准时间
  var d1 = DateTime.parse('2021-01-20 12:30:30');
  print(d1);
  var d2 = DateTime.parse('2021-01-20 12:30:30+0800');
  print(d2);

  // 时间增量
  print(now.add(new Duration(hours: 2)));
  print(now.add(new Duration(hours: -3)));

  // 时间比较
  print(d1.isAfter(d2)); // d1 是否在 d2 之后
  print(d1.isBefore(d2)); // d1 是否在 d2 之前
  print(d1.isAtSameMomentAs(d2)); // d1 与 d2 是否相同

  // 时间差
  var d3 = new DateTime(2021, 1, 1);
  var d4 = new DateTime(2021, 1, 4);
  var difference = d3.difference(d4);
  print([difference.inDays, difference.inHours]); // d1与d2相差的天数与小时

  // 时间戳
  print(now.millisecondsSinceEpoch); // 单位毫秒,13 位时间戳
  print(now.microsecondsSinceEpoch); // 单位微秒, 16 位时间戳

  // 格式化
  print(now.month.toString().padLeft(2, '0'));

  String timestamp = "${now.year.toString()}-${now.month.toString().padLeft(2,'0')}-${now.day.toString().padLeft(2,'0')} ${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}";
  print(timestamp);
}

三十四、第三方库

  • 来源
    • https://pub.dev https://pub. flutter-io. cn/packages
    • https://pub. dartlang. org/flutter
  • 使用
    • 在项目目录下创建 pubspec. yam
    • 在 pubspec. yaml 中声明第三方库(依赖)
    • 命令行中进入 pubspec.yaml 所在目录,执行 pub get 进行安装
    • 项目中引入已安装的第三方库(import ‘package:xxxxx/xxxxx.dart’)

第三方库

  • 第三方库的结构
  • 一个第三方库,必须包含一个 pubspec.yaml
  • pubspec.yaml
  • 详情 : https://dart.cn/tools/pub/pubspec

在这里插入图片描述

三十五、extension (扩展)

  • extension 关键字在 Dart 2.7 及其以上才支持
    • sdk: “>=2.7.0 ❤️.0.0”
  • extension 可以扩展对象的内容
    • extension StringExtension on String {// 扩展的内容}
    • 扩展不仅可以定义方法,还可以定义 setter, getter, operator
  • 使用
    • 声明扩展
    • 引入扩展
    • 使用扩展(String.扩展内容)
      在这里插入图片描述

三十六、call

  • 在类中可以声明 call方法(方法名不能变)
  • 当我们将类的实例,用作函数时,会自动调用call方法

在这里插入图片描述

三十七、noSuchMethod

  • 当我们调用了一个类的,未定义的方法时,Dart 会自动调noSuchMethod
  • 使用前提
    • 类中声明了 noSuchMethod (否则调默认的 noSuchMethod)
    • 实例化对象必须用 dynamic 来修饰
      • dynamic p = Person();
    • 调用的是未定义方法(p.undefinedMethod())

在这里插入图片描述

三十八、hashCode

  • hashCode 是 Dart 对象的唯一标识
  • hashCode 表现为一串数字
  • Dart 中的每个对象都有hashCode
  • 我们可以通过 hashCode 来判断两个对象是否相等
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值