flutter-dart菜鸟入门

3,662 阅读9分钟

flutter-dart菜鸟入门

本人是一名Android开发,这是个人在学习flutter的过程中对dart的一些学习总结和自己的理解,如果发现什么写的不对的地方,请勿喷

本文只是简单介绍开发flutter的dart的常用用法,强烈建议阅读官方文档dart中文网地址

1. 为什么要介绍dart?

因为 Flutter 需要使用Dart语言开发;

2. 基本数据类型

  • num 数字, 包括整数和浮点数
  • int 整数
  • double 浮点数
  • String 字符串
  • bool 布尔值

3. 重要的概念

  • dart所有对象类都继承 Object
  • dart所有变量都是对象,包括数字、null等都是对象
  • dart所有类型变量的默认值全是null(包括数字类型和布尔类型)
  • dart跟Java不同,没有 public、 protected、 和 private 修饰符;私有变量以 (_) 开头,否则是就是公有的
  • 当dart 需要一个布尔值的时候,只有 true 对象才被认为是 true,其他任何情况都是false,这点和 JavaScript 不一样
  • dart支持高阶函数、顶级函数、顶级变量、静态函数、静态变量等

4. 定义变量

用var定义一个可变类型的变量

var name = 'Bob';
name = 1;
name = false;

定义具体类型的变量

String name = 'Bob'; // 定义一个字符串变量
bool flag = false; // 定义一个布尔类型变量
int age = 10; // 定义一个整数变量

建议:成员变量使用具体的类型,var只在局部变量中使用。代码风格

5. 定义常量

支持使用final和const定义常量

  • final 变量只能赋值一次
  • const 变量是编译时常量(Const 变量同时也是 final 变量)
final name = 'Bob';
const bar = 1000000;
const atm = 1.01325 * bar;

6. const 其他用法

创建不变的值

var foo = const []; // 定义一个不可变的集合
boo.add(1); // error

定义常量构造函数

class A {
  const A();
}
A a1 = const A();
A a2 = const A();
print(a1 == a2); // true

7. 字符串

  • 可以使用单引号或者双引号来创建字符串
  • 在字符串中可以使用${expression}表达式
  • 可以使用三个单引号或者双引号创建多行字符串
var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
var s3 = "expression $s2";
var s4 = "expression ${s2.toUpperCase()}";
var s5 = '''
You can create
multi-line strings like this one.
''';
var s6 = """This is also a
multi-line string.""";

8. 定义class

  • 所有的类都继承于 Object
  • 不支持多继承,但支持基于 mixin 的继承机制,意味着每个类(Object 除外) 都只有一个超类
  • 无法像java一样直接定义interface,但支持隐式接口,每个类都隐式的定义了一个包含所有实例成员的接口, 并且这个类实现了这个接口
  • 使用abstract 修饰符定义一个抽象类,抽象类通常用来定义接口, 以及部分实现
// 定义class Person
class Person {
  // In the interface, but visible only in this library.
  final _name;
  // Not in the interface, since this is a constructor.
  Person(this._name);
  // In the interface.
  String greet(who) => 'Hello, $who. I am $_name.';
}
// 定义Imposter 实现Person隐式的interface
class Imposter implements Person {
  // 需要实现interface _name属性
  final _name = "";
  // 需要实现interface greet方法
  String greet(who) => 'Hi $who. Do you know who I am?';
}
// 定义Imposter1 继承Person类
class Imposter1 extends Person {
  Imposter1(name) : super(name);
}

定义抽象类

abstract class AbstractContainer {
  // 抽象方法不需要用abstract修饰符
  void updateChildren();
}
// 继承抽象类
class SpecializedContainer extends AbstractContainer {
  // 实现抽象方法
  void updateChildren() {
    // ...Implement updateChildren()...
  }
}
// 实现抽象类AbstractContainer 隐式的interface
class SpecializedContainer1 implements AbstractContainer {
  // 实现interface的方法
  void updateChildren() {
    // ...Implement updateChildren()...
  }
}

9. mixin 继承机制(为类添加新的功能)

  • 定义mixin 跟定义class一样,但是不能有构造函数,连无参的构造函数都不行;因为每个Mixin都有一个自定义的构造函数被单独调用,父类也是如此,因此Mixin的构造函数不能够被声明,调用函数可以省略
  • 使用 with 关键字 使用mixin
  • 使用mixin定义的class,是所有mixin类的子类
class A {
  void printA() {
    print("A");
  }
}
class B {
  void printB() {
    print("B");
  }
}
abstract class C {
  void printC();
}
// 第一种使用Mixin的方式
class D extends A with B, C {
  @override
  void printC() {
    print("C");
  }
  void printD() {
    print("D");
  }
}
// 第二种使用Mixin的方式
// 这种方法无法定义class的实体
// 因为C 是有一个抽象方法,所以定义的E 需要abstract声明
abstract class E = A with B, C;
class E1 extends E {
  @override
  void printC() {
    print("C");
  }
  void printE() {
    print("E");
  }
}
D d = new D();
d.printA(); // A
d.printB(); // B
d.printC(); // C
d.printD(); // D
print(d is C); // true
print(d is B); // true
print(d is A); // true
E1 e1 = new E1();
e1.printA(); // A
e1.printB(); // B
e1.printC(); // C
e1.printE(); // E
print(e1 is E); // true
print(e1 is C); // true
print(e1 is B); // true
print(e1 is A); // true

10. 构造函数

  • 默认构造函数,默认构造函数没有参数
  • 支持命名构造函数;命名构造函数来更清晰的表明你的意图
  • 支持常量构造函数;为一个类提供一个状态不变的对象, 且类的所有变量必需声明为 final类型
  • 支持工厂方法构造函数;使用factory 来定义 这个构造函数 构造函数执行顺序:
  1. initializer list(初始化参数列表), 使用逗号分隔初始化表达式。
  2. superclass’s no-arg constructor(超类的无名构造函数)
  3. main class’s no-arg constructor(主类的无名构造函数)

命名构造函数

class Person {
  String firstName;
  
  // 命名构造函数
  Person.fromJson(Map data) {
    print('in Person');
  }
}
class Employee extends Person {
  // 必需调用父类的构造函数
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}
class Point {
  num x;
  num y;
  Point(this.x, this.y);
  // 初始化 x、y 参数列表
  Point.fromJson(Map jsonMap)
      : x = jsonMap['x'],
        y = jsonMap['y'] {
    print('In Point.fromJson(): ($x, $y)');
  }
}
main() {
  var emp = new Employee.fromJson({});
}

常量构造函数

class ImmutablePoint {
  final num x;
  final num y;
  const ImmutablePoint(this.x, this.y);
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);
}

工厂方法构造函数

class Logger {
  final String name;
  bool mute = false;
  // _cache is library-private, thanks to the _ in front
  // of its name.
  static final Map<String, Logger> _cache =
      <String, Logger>{};
  factory Logger(String name) {
    if (_cache.containsKey(name)) {
      return _cache[name];
    } else {
      final logger = new Logger._internal(name);
      _cache[name] = logger;
      return logger;
    }
  }
  Logger._internal(this.name);
  void log(String msg) {
    if (!mute) {
      print(msg);
    }
  }
}
var logger = new Logger('UI');
logger.log('Button clicked');

11. getters and setters方法

  • 没有final修饰符的变量,隐含的具有 getter和setter方法
  • final修饰符的变量,隐含的具有 getter方法
class Rectangle {
  num left;
  num top;
  num width;
  num height;
  Rectangle(this.left, this.top, this.width, this.height);
  // Define two calculated properties: right and bottom.
  num get right             => left + width;
      set right(num value)  => left = value - width;
  num get bottom            => top + height;
      set bottom(num value) => top = value - height;
}

12. 流程控制语句(基本跟其他语言一样)

  • 支持if else
  • 支持标准的 for 循环
  • 对于实现了 Iterable 接口的类,支持 for-in 循环
  • 支持While and do-while 循环
  • 支持break和continue 终止和继续下一次循环
  • 支持switce case语句;每个非空的 case 语句都必须有一个 break 语句
// if else
if (isRaining()) {
  you.bringRainCoat();
} else if (isSnowing()) {
  you.wearJacket();
} else {
  car.putTopDown();
}
// for循环
var message = new StringBuffer("Dart is fun");
for (var i = 0; i < 5; i++) {
  message.write('!');
}
// for-in循环
var collection = [0, 1, 2];
for (var x in collection) {
  print(x);
}
// while 循环
while (!isDone()) {
  doSomething();
}
// do-while 循环
do {
  printLine();
} while (!atEndOfPage());
// switce case语句
var command = 'OPEN';
switch (command) {
  case 'CLOSED':
    executeClosed();
    break;
  case 'PENDING':
    executePending();
    break;
  default:
    executeUnknown();
}

13. 操作符(基本跟其他语言一样)

  • 支持 condition ? expr1 : expr2 表达式
  • 支持 expr1 ?? expr2; 如果 expr1 是 non-null,返回其值; 否则执行 expr2 并返回其结果
  • 支持?.操作符,避免空指针异常
  • 级联操作符(..)
  • 支持位和移位操作符, &、|、^、~expr、<<、>>
  • 支持逻辑操作符,!expr、||、&&
// ?.操作符
var p = new Point(2, 2);
p?.y = 4;
// ?? 操作符
b ??= value; // 如果 b 是 null,则赋值给 b;
// 级联操作符(..)
// 第一个方法 querySelector() 返回了一个 selector 对象。 后面的级联操作符都是调用这个对象的成员, 并忽略每个操作 所返回的值
querySelector('#button') // Get an object.
  ..text = 'Confirm'   // Use its members.
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));

14. Lists(列表)

Dart 中数组就是 List 对象 简单创建list

var list1 = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
list[1] = 1;
assert(list[1] == 1);

使用构造函数创建list

var list2 = new List();
list2.add(1);
assert(list2[0] == 1);

15. Map

简单创建 map

var gifts = {
// Keys      Values
  'first' : 'partridge',
  'second': 'turtledoves',
  'fifth' : 'golden rings'
};

使用 Map 构造函数创建Map

var gifts = new Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';

16. Functions(方法)

  • 所有的方法都是Function类型
  • 支持高阶函数,可以当作另一个方法的参数
  • 如果方法之后一个表达式,可以使用 => expr 语法, 这个 => expr 语法是 { return expr; } 形式的缩写
  • 支持闭包,在方法內定义方法
  • 支持可选参数,包括可选命名参数和可选位置参数
  • 支持默认参数值
  • 所有的函数都返回一个值。如果没有指定返回值,则 默认把语句 return null; 作为函数的最后一个语句执行。
// 简单的定义一个方法
bool isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}
// => expr表达式用法
// 注意: 在箭头 (=>) 和冒号 (;) 之间只能使用一个 表达式 – 不能使用 语句。 例如:你不能使用 if statement,但是可以 使用条件表达式
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;

可选命名参数: 在定义方法的时候,使用 {param1, param2, …} 的形式来指定命名参数, 调用方法的时候,你可以使用这种形式 paramName: value 来指定命名参数

// 定义
enableFlags({bool bold, bool hidden}) {
  // ...
}
// 定义带有默认值的方法
void enableFlags1({bool bold = false, bool hidden = false}) {
  // ...
}
// 使用
enableFlags(bold: true, hidden: false);

可选位置参数:把一些方法的参数放到 [] 中就变成可选 位置参数了

String say(String from, String msg, [String device = 'carrier pigeon', String mood]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  if (mood != null) {
    result = '$result (in a $mood mood)';
  }
  return result;
}
// 不使用可选参数
say('Bob', 'Howdy'); // Bob says Howdy
// 使用可选参数
say('Bob', 'Howdy', 'smoke signal'); // Bob says Howdy with a smoke signal

17. Exceptions(异常)

  • Dart 提供了 Exception 和 Error 类型, 以及一些子类型
  • 与java不同,不能在定义方法的时候声明异常, 即Dart 异常是非检查型异常
  • 使用 throw 关键词抛出异常, 支持抛出任意的对象
  • 使用 try cache finally捕获异常,同时支持用 rethrow 重新抛出异常
try {
  // do something
} on Exception catch (e) {
  print(e);
  // 重新抛出这个异常
  rethrow;
} catch (e) {
  print(e);
  // 抛出任意的对象
  throw 'Out of llamas!';
} finally {
  print("finally");
}

18. 泛型

// 定义支持的泛型类
abstract class Cache<T> {
  T getByKey(String key);
  setByKey(String key, T value);
}
// 定义泛型函数
T first<T>(List<T> ts) {
  // ...Do some initial work or error checking, then...
  T tmp ?= ts[0];
  // ...Do some additional checking or processing...
  return tmp;
}

19. 枚举类型

  • 无法继承枚举类型、无法使用 mix in、无法实现一个枚举类型
  • 无法显示的初始化一个枚举类型
enum Color {
  red,
  green,
  blue
}

20. 异步支持

  • 支持 async await,(跟es6的async await差不多)
  • 使用 Future 或者 Stream执行异步操作
  • 支持在循环中使用异步
checkVersion() async {
  var version = await lookUpVersion();
  if (version == expectedVersion) {
    // Do something.
  } else {
    // Do something else.
  }
}
try {
  checkVersion();
} catch (e) {
  print(e);
}
// 在循环中使用异步
await for (var request in requestServer) {
  handleRequest(request);
}

21. Typedefs 给方法类型命名,保留类型信息

typedef int Compare(Object a, Object b);
class SortedCollection {
  Compare compare;
  SortedCollection(this.compare);
}
 // Initial, broken implementation.
 int sort(Object a, Object b) => 0;
main() {
  SortedCollection coll = new SortedCollection(sort);
  assert(coll.compare is Function);
  assert(coll.compare is Compare);
}

22. 注释

  • 单行注释以 //
  • 多行注释以 /* 开始, */ 结尾
  • 文档注释可以使用 /// 开始

23. 导包

使用 import 来指定一个库如何使用另外 一个库。

  • 对于内置的库,URI 使用特殊的 dart: scheme
  • 对于其他的库,你可以使用文件系统路径或者 package: scheme
  • 如果两个库具有冲突的标识符,可以使用库的前缀来区分
  • 支持导入库的一部分
  • 支持延迟载入库
// 导入内置的库
import 'dart:async';
import 'dart:io';
// 导入其他的库
import 'package:flutter/material.dart';
// 使用库的前缀来解决冲突
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// Import only foo.
import 'package:lib1/lib1.dart' show foo;
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
// 延迟载入库
import 'package:deferred/hello.dart' deferred as hello;
greet() async {
  await hello.loadLibrary();
  hello.printGreeting();
}