轻松掌握Dart编程基础

发表时间: 2021-04-14 17:39

变量类型

// 通过 var 定义的变量会自动推导变量类型var text = 'Hello world';

字符串

String str = '你好 dart';

Number 类型

int

整数值;长度不超过 64位

int num = 123456;

double

64位的双精度浮点数字

int x = 1.252256;

布尔

bool isBool = true;print(isBool);// 不允许使用 if(value) 或者 assert(value) 的方式来检查布尔值//var fullName = '';//if (fullName) {//  print(111);//}// 检查是否为空字符串 .var fullName = '';assert(fullName.isEmpty);// 检查是否小于等于零。var hitPoints = 0;assert(hitPoints <= 0);// 检查是否为 null。var unicorn;assert(unicorn == null);// 检查是否为 NaN。var iMeantToDoThis = 0 / 0;assert(iMeantToDoThis.isNaN);数组 集合类型

数组 集合类型

// 类型推导var list1 = [1, 2, 3];// 字面量var list2 = [];list2.add('张三');list2.add('李四');list2.add('王五');// 定义 List 指定类型var list3 = <String>[];list3.add('张三');

Map(对象)

// 字面量var person = {  "name":"张三",  "age":20};// 使用构造器  这里的 new 关键词可以省略var gifts = new Map();gifts['first'] = 'partridge';gifts['second'] = 'turtledoves';gifts['fifth'] = 'golden rings';

Final 和 Const

一个 final 变量只可以被赋值一次;一个 const 变量是一个编译时常量(const 变量同时也是 final 的)。顶层的 final 变量或者类的 final 变量在其第一次使用的时候被初始化。

final name = 'Bob';final String nickname = 'Bobby';var foo = const [];final bar = const [];const baz = []; // 相当于 `const []` (Equivalent to `const []`)

运算符

算术运算符

int a = 18;int b = 5;print(a - b); // 减print(a + b); // 加print(a * b); // 乘print(a / b); // 除print(a % b); // 取余print(a ~/ b); // 取整

自增自减操作

var a, b;a = 0;b = ++a; // 在 b 赋值前将 a 增加 1。assert(a == b); // 1 == 1a = 0;b = a++; // 在 b 赋值后将 a 增加 1。assert(a != b); // 1 != 0a = 0;b = --a; // 在 b 赋值前将 a 减少 1。assert(a == b); // -1 == -1a = 0;b = a--; // 在 b 赋值后将 a 减少 1。assert(a != b); // -1 != 0

关系运算

int a = 5;int b = 3;print(a == b);print(a != b);print(a > b);print(a < b);print(a >= b);print(a <= b);

逻辑运算符

// 取反bool flag = false;print(!flag);// && 并且:全部为true的话值为true,否则为falsebool a = true;bool b = false;print(a && b);// || 或与:全部为false的话值为false,否则为truebool c = false;bool d = false;print(c || d);

类型判断运算符

is 如果对象是指定类型则返回 true

var str = '123';if (str is String) {  print('String 类型');} else if (str is int) {  print('int 类型');}

is! 如果对象是指定类型则返回 false

var str = '123';if(str is! String){  print('String 类型');}

赋值运算符

??=

如果b为空,就把23赋值给b

var b;b ??= 23;

条件表达式

三目运算

// 根据布尔表达式bool isPublic = true;var visibility = isPublic ? 'public' : 'private';// 根据判定是否为 nullString playerName(String name) => name ?? 'Guest';

级联运算符

级联运算符(..)可以让你在同一个对象上连续调用多个对象的变量或方法。

// 数组集合的级联List<int> listInt = []    ..add(0)    ..add(1)    ..add(2)    ..removeAt(1);  print(listInt); // output: [0, 2]// 对象字典的级联Map<String,dynamic> aMap = Map()    ..putIfAbsent('name', ()=>'bill')    ..putIfAbsent('name', ()=>'gate')    ..addAll({'sex':'male', 'age':1})    ..remove('age');  print(aMap); // output: {name: bill, sex: male}

类型转换

String 转 Number

String str = '123';var num = int.parse(str);print(num is int);var num2 = double.parse(str);print(num2 is int);// double 可以转 int,但是 int 不能转换 double 类型数字。值为空时报错

Number 转 String

var number = 12;var str = number.toString();print(str is String);

其它类型转换成Boolean类型

// 字符串转布尔var str = '123';if (str.isEmpty) {  print('str 为空');} else {  print('str 不为空');}// 数字转布尔var num = 123;if (num == 0) {  print(0);} else {  print('非0');}

集合类型 List Set Map

List

常用属性和方法

常用属性:

  • length 长度
  • reversed 翻转
  • isEmpty 是否为空
  • isNotEmpty 是否不为空
List list = ['香蕉', '苹果', '西瓜', '梨子', '草莓'];print(list.length);       // 5print(list.isEmpty);      // falseprint(list.isNotEmpty);   // trueprint(list.reversed.toList());

常用方法:

  • add 增加
  • addAll 拼接数组
  • indexOf 查找 传入具体值,返回索引,查找不到返回-1
  • remove 删除 传入具体值
  • removeAt 删除 传入索引值
  • fillRange 修改
  • insert(index,value) 指定位置插入
  • insertAll(index,list) 指定位置插入List
  • toList() 其它类型转换成List
  • join() List转换成字符串
  • split() 字符串转换成List
  • forEach
  • map
  • where
  • any
  • every
List list = ['香蕉', '苹果', '西瓜', '梨子', '草莓'];list.add('地瓜');print(list);list.addAll(['桃子', '葡萄']);print(list);print(list.indexOf('梨子'));list.remove('葡萄');print(list);list.removeAt(2);print(list);list.fillRange(1, 2, '柿子');print(list);list.insert(1, '');print(list);list.insertAll(1, ['', '']);print(list);var str = list.join(',');print(str);list = str.split(',');print(list);list.forEach((element) {  print(element);});for (var i = 0; i < list.length; i++) {  print(list[i]);}for (var item in list) {  print(item);}
List list = [1, 2, 3, 4, 5, 6, 7];// 遍历集合,返回新的集合var newList = list.map((value) {  return value * 2;});print(newList);// 返回满足条件的集合var newList = list.where((value) {  return value > 5;});print(newList.toList());// 只要满足条件的就返回truevar f = list.any((value) {  return value > 5;});print(f);  // true// 每一个都要满足条件才返回true,否则falsevar f = list.every((value) {  return value > 5;});print(f);

Set

定义集合

var s = new Set();s.add('香蕉');s.add('苹果');s.add('苹果');print(s); // {香蕉, 苹果}  集合去重print(s.toList());
List list = ['香蕉', '苹果', '西瓜', '梨子', '草莓', '西瓜', '苹果'];var s = new Set();s.addAll(list);print(s);print(s.toList());
List list = ['香蕉', '苹果', '西瓜', '梨子', '草莓', '西瓜', '苹果'];var s = new Set();s.addAll(list);s.forEach((element) => print(element));

Map

常用属性和方法

常用属性:

  • keys 获取所有的key值
  • values 获取所有的value值
  • isEmpty 是否为空
  • isNotEmpty 是否不为空

常用方法:

  • remove(key) 删除指定key的数据
  • addAll({…}) 合并映射 给映射内增加属性
  • containsValue 查看映射内的值,返回true/false
  • map

定义

Map person = {'name': '张三', 'age': 20};Map student = new Map();student['name'] = '李四';
Map person = {'name': '张三', 'age': 20};print(person.keys.toList());print(person.values.toList());print(person.isEmpty);print(person.isNotEmpty);
Map person = {'name': '张三', 'age': 20, 'sex': '男'};person.addAll({  'work': ['前端工程师', '安卓工程师'],  'height': 168});person.remove('sex');print(person.containsKey('张三'));print(person.containsValue('张三'));print(person);
Map person = {'name': '张三', 'age': 20, 'sex': '男'};person.forEach((key, value) {  print("$key ---- $value");});

函数

定义函数

返回类型 方法名称(参数1,参数2,...){  方法体  return 返回值;}
void main() {  printInfo();  print(getNum());  print(printUserInfo());  print(getList());}void printInfo() {  print('自定义方法');}int getNum() {  return 123;}String printUserInfo() {  return '用户名';}List getList() {  return [1, 2, 3];}

简写

如果函数体内只包含一个表达式,你可以使用简写语法

bool isBool(int num) => num > 1

函数参数

函数可以有两种形式的参数:必要参数 和 可选参数。必要参数定义在参数列表前面,可选参数则定义在必要参数后面。可选参数可以是 命名的 或 位置的。

必要参数

String printUserInfo(String username, int age) { // 形参  return "姓名:$username---年龄:$age";}print(printUserInfo('张三', 18)); // 实参

可选参数

String printUserInfo(String username, [int? age]) {  if (age != null) {    return "姓名:$username---年龄:$age";  }  return "姓名:$username---年龄:保密";}

默认参数

String printUserInfo(String username, [int? age, String sex = "男"]) {  if (age != null) {    return "姓名:$username---性别:$sex---- 年龄:$age";  }  return "姓名:$username---性别:$sex---年龄:保密";}

命名参数

String printUserInfo(String username, {int? age, String sex = "男"}) {  if (age != null) {    return "姓名:$username---性别:$sex---- 年龄:$age";  }  return "姓名:$username---性别:$sex---年龄:保密";}printUserInfo('张三', age: 20)

将函数作为参数传递给另一个函数

void fn1() {  print('fn1');}void fn2(fn) {  fn();}fn2(fn1);

箭头函数

List list = [1, 2, 3, 4, 5];list.forEach((element) => print(element));list.forEach((element) => {  print(element)});var newList = list.map((e) => e > 2 ? e * 2 : e);print(newList.toList());

匿名函数

var printNum = (int num) {  print(num);};printNum(123);

自执行函数

((n) {    print('自执行函数 $n');  })(1);

闭包函数

全局变量常驻内存,全局变量污染全局。
局部变量不常驻会被垃圾机制回收,不会污染全局

函数嵌套函数,内部函数会调用外部函数的变量或参数.并reutrn里面的函数

Function makeAdder(int addBy) {  return (int i) => addBy + i;}var add2 = makeAdder(2);print(add2(2));

创建类

class Person {  String name = '张三';  int age = 28;  void getInfo() {    print("$name --- $age");    print("${this.name} --- ${this.age}");  }}Person p1 = new Person();print(p1.name);p1.getInfo();

构造函数

如果你没有声明构造函数,那么 Dart 会自动生成一个无参数的构造函数并且该构造函数会调用其父类的无参数构造方法。子类不会继承父类的构造函数,如果子类没有声明构造函数,那么只会有一个默认无参数的构造函数。

默认构造函数
声明一个与类名一样的函数即可声明一个构造函数

class Person {  String name;  int age;  // 默认构造函数,实例化时触发  Person(this.name, this.age);  void printInfo() {    print("${this.name} --- ${this.age}");  }}Person p1 = new Person('张三', 20);

命名式构造函数

可以为一个类声明多个命名式构造函数来表达更明确的意图。

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

私有属性和方法

通过给属性和方法加上下划线 _,将属性和方法变成私有的。

class Animal {  String _name;  int age;  Animal(this._name, this.age);  String getName() {    return this._name;  }  void _run() {    print('私有方法');  }  execRun() {    // 类里面的方法互相调用    this._run();  }}

getter 和 setter

class Rect {  num height;  num width;  Rect(this.height, this.width);  get area {    return this.width * this.height;  }  set areaHeight(value) {    this.height = value;  }}Rect a = new Rect(10, 4);print(a.area);a.areaHeight = 50;print(a.height);

初始化列表

class Person {  String name;  int age;  //在构造函数执行之前进行初始化变量  Person(): name = '张三',age = 26;  void printInfo() {    print("${this.name} --- ${this.age}");  }}

静态成员

  1. 使用static关键字来实现类级别的变量和函数
  2. 静态方法不能访问非静态成员,非静态方法可以访问静态成员
class Person {  static String name = '张三';  int age = 20;  static void show() {    print(name);  }  void printInfo() {    print(name);  // 访问静态属性    print(this.age); // 访问非静态属性    show();   // 调用静态方法  }}Person.show();Person().printInfo();

对象操作符

  • ? 条件运算符
  • as 类型转换
  • is 类型判断
  • .. 级联操作
class Person {  String name;  int age;  Person(this.name, this.age);  void printInfo() {    print(this.name);    print(this.age);  }}Person p = new Person('张三', 18);if (p is Person) {  p.name = '李四';}p.printInfo();var p1;p1 = '';p1 = new Person('张三', 18);(p1 as Person).printInfo();p1.printInfo();Person p2 = Person('占山', 20);p2  ..name = '张三'  ..age = 56  ..printInfo();

继承

  1. 子类使用extends关键词来继承父类
  2. 子类会继承父类里面可见的属性和方法,但是不会继承构造函数,和静态方法
  3. 子类会覆写父类的方法 getter和setter
void main() {  Student s = Student('张三', 15, '男');  // 子类继承父类的属性和方法  s.printInfo();  s    ..name = '李四'    ..age = 18    ..printInfo();  s.eat();  s.say();}class Person {  String name;  int age;  Person(this.name, this.age);  Person.birth(this.name, this.age);  void printInfo() {    print(this.name);    print(this.age);  }  say() {    print("${this.name} --- ${this.age}");  }  static void teaching() {    print('父类静态方法');  }  void eat() {    print('Person类的eat方法');  }}class Student extends Person {  String? sex; // 如果字段或变量不能在声明中初始化,但总是在引用之前初始化,则将其标记为延迟  // : super 初始化列表 给父类构造函数传参  Student(String name, int age, String sex) : super(name, age) {    this.sex = sex;  }  // 命名构造函数传参  // Student(String name, int age, String sex) : super.birth(name, age) {  //   this.sex = sex;  // }  @override  say() {    print("${this.name} --- ${this.age} --- ${this.sex}");  }  // 覆写父类的方法  @override  void eat() {    print('Student类的eat方法');  }}

抽象类

抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口

  1. 抽象类通过abstract关键字定义。
  2. 抽象方法不能用 abstract 声明,Dart中没有方法体的方法我们称为抽象方法。
  3. 如果子类继承抽象类必须得实现里面的抽象方法。
  4. 如果把抽象类当作接口实现的话必须得实现抽象类里面定义的所有属性和方法。
  5. 抽象类不能被实例化,只有继承它得子类可以。

extends 抽象类和 implements 的区别:

  1. 如果要复用抽象类里面得方法,并且要用抽象方法约束自类得话我们就用extends继承抽象类
  2. 如果只是把抽象类当作标准得话我们就用implements实现抽象类

多态

父类定义一个方法不去实现,让继承它得子类去实现,每个子类又不同得表现

void main() {  Dog d = new Dog();  d.eat();  Cat c = Cat();  c.eat();}abstract class Animal {  eat();}class Dog extends Animal {  @override  eat() {    print('小狗在吃骨头');  }}class Cat extends Animal {  @override  eat() {    print('小猫在吃');  }}

子类得实例赋值给父类得引用

void main() {  Animal d = new Dog();  d.eat();  Animal c = Cat();  c.eat();}abstract class Animal {  eat();}class Dog extends Animal {  @override  eat() {    print('小狗在吃骨头');  }}class Cat extends Animal {  @override  eat() {    print('小猫在吃');  }}

接口

abstract class Db {  String? uri;  add(String data);  save();  delete();}
import 'Db.dart';class Mysql implements Db {  @override  String? uri;  Mysql(this.uri);  @override  add(data) {    print('这是mysql得add方法' + data);  }  @override  delete() {    // TODO: implement delete    throw UnimplementedError();  }  @override  save() {    // TODO: implement save    throw UnimplementedError();  }}
import 'Db.dart';class MsSql implements Db {  @override  String? uri;  @override  add(data) {    print('这是mssql得add方法' + data);  }  @override  delete() {    // TODO: implement delete    throw UnimplementedError();  }  @override  save() {    // TODO: implement save    throw UnimplementedError();  }}

一个类实现多个接口

void main() {  C c = C();  c.printA();  c.printB();}abstract class A {  String? name;  printA();}abstract class B {  String? name;  printB();}class C implements A, B {  @override  String? name;  @override  printA() {    print('printA');  }  @override  printB() {    print('printB');  }}

Mixin

在类中混入其它功能,可以使用mixins实现类似多继承的功能。

  1. 作为mixins的类只能继承自Object,不能继承其它类
  2. 作为mixins的类不能又构造函数
  3. 一个类可以mixins多个mixins类
  4. mixins绝不是继承,也不是接口,而是一种全选的特性
void main() {  C c = C('张三', 18);  c.printA();  c.printB();  print(c.label);  print(c.text);  print(c.name);  c.printInfo();}class Person {  String? name;  int age;  Person(this.name, this.age);  printInfo() {    print("${this.name}---${this.age}");  }}mixin A {  String label = 'this is A';  void printA() {    print('printA');  }}mixin B {  String text = 'this is B';  void printB() {    print('printB');  }}class C extends Person with A, B {  C(String? name, int age) : super(name, age);}

泛型

泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型检查)

泛型方法

void main() {  // 不检查类型  print(getData('Hello'));  print(getData(123));  // 检查类型  print(getData<String>('Hello Dart'));}T getData<T>(T value) {  return value;}

泛型类

内置泛型类

void main() {  List names = <String>[];  names.addAll(['Seth', 'Kathy', 'Lars']);}

自定义泛型类

void main() {  PrintClass p = PrintClass();  p.add(1);  p.add(12);  p.add('Hello');  p.printList();  PrintClass p2 = PrintClass<String>();  //p2.add(1); // 只能传入 String 类型  p2.add('Hello');  p2.printList();}class PrintClass<T> {  List list = <T>[];  void add(T value) {    this.list.add(value);  }  void printList() {    print(this.list);  }}

泛型接口

void main() {  MemoryCache m1 = MemoryCache<String>();  m1.setByKey('key', 'value');  MemoryCache m2 = MemoryCache<Map>();  m2.setByKey('key', {"name": "张三", "age": 20});}abstract class Cache<T> {  getByKey(String key);  void setByKey(String key, T value);}class FileCache<T> implements Cache<T> {  @override  getByKey(String key) {    return key;  }  @override  void setByKey(String key, T value) {    print("文件缓存 存储 key=${key}  value=${value}");  }}class MemoryCache<T> implements Cache<T> {  @override  getByKey(String key) {    return key;  }  @override  void setByKey(String key, T value) {    print("内存缓存 存储 key=${key}  value=${value}");  }}