Flutter学习记录(一)Dart学习

583 阅读4分钟

代码规范

顺序

为了使文件前面部分保持整洁,我们规定了关键字出现顺序的规则。每个“部分”应该使用空行分割。

要把 “dart:” 导入语句放到其他导入语句之前。

要把 “package:” 导入语句放到项目相关导入语句之前。

import 'dart:async';
import 'dart:html';

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

import 'util.dart';

推荐 把外部扩展 “package:” 导入语句放到其他语句之前。

如果你使用了多个 “package:” 导入语句来导入自己的包以及其他外部扩展包,推荐将自己的包分开放到一个额外的部分。

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

import 'package:my_package/util.dart';

要 把导出(export)语句作为一个单独的部分放到所有导入语句之后。

import 'src/error.dart';
import 'src/foo_bar.dart';

export 'src/error.dart';

变量

在 Dart 中,未初始化的变量拥有一个默认的初始化值:null。即便数字也是如此,因为在 Dart 中一切皆为对象,数字也不例外。

int lineCount;
assert(lineCount == null);

var

在Dart中用var声明一个变量后,Dart在编译时会根据第一次赋值数据的类型来推断其类型,编译结束后其类型就已经被确定。

dynamic和Object

Object 是Dart所有对象的根基类,也就是说所有类型都是Object的子类(包括Function和Null),所以任何类型的数据都可以赋值给Object声明的对象. dynamic与var一样都是关键词,声明的变量可以赋值任意对象。 而dynamic与Object相同之处在于,他们声明的变量可以在后期改变赋值类型。

dynamic t;
 Object x;
 t = "hi world";
 x = 'Hello Object';
 //下面代码没有问题
 t = 1000;
 x = 1000;

dynamic与Object不同的是,dynamic声明的对象编译器会提供所有可能的组合, 而Object声明的对象只能使用Object的属性与方法, 否则编译器会报错。

dynamic的这个特性与Objective-C中的id作用很像. dynamic的这个特点使得我们在使用它时需要格外注意,这很容易引入一个运行时错误.

final和const

如果您从未打算更改一个变量,那么使用 final 或 const,不是var,也不是一个类型。 一个 final 变量只能被设置一次,两者区别在于:const 变量是一个编译时常量,final变量在第一次使用时被初始化。被final或者const修饰的变量,变量类型可以省略,如:

//可以省略String这个类型声明
final str = "hi world";
//final String str = "hi world"; 
const str1 = "hi world";
//const String str1 = "hi world";

函数

Dart是一种真正的面向对象的语言,所以即使是函数也是对象,并且有一个类型Function。这意味着函数可以赋值给变量或作为参数传递给其他函数,这是函数式编程的典型特征。

Dart函数声明如果没有显式声明返回值类型时会默认当做dynamic处理,注意,函数返回值没有类型推断。

bool isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}
typedef bool CALLBACK();

//不指定返回类型,此时默认为dynamic,不是bool
isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}
void test(CALLBACK cb){
   print(cb()); 
}
//报错,isNoble不是bool类型
test(isNoble);

级联运算符(..)

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

比如下面的代码:

querySelector('#confirm') // 获取对象 (Get an object).
  ..text = 'Confirm' // 使用对象的成员 (Use its members).
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));

第一个方法 querySelector 返回了一个 Selector 对象,后面的级联操作符都是调用这个 Selector 对象的成员并忽略每个操作的返回值。

上面的代码相当于:

var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.lis

ten((e) => window.alert('Confirmed!')); 级联运算符可以嵌套,例如:

final addressBook = (AddressBookBuilder()
      ..name = 'jenny'
      ..email = 'jenny@example.com'
      ..phone = (PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();

使用类的成员 对象的 成员 由函数和数据(即 方法 和 实例变量)组成。方法的 调用 要通过对象来完成,这种方式可以访问对象的函数和数据。

使用(.)来访问对象的实例变量或方法:

var p = Point(2, 2);
// 为实例变量 y 赋值。
p.y = 3;
// 获取 y 的值。
assert(p.y == 3);
// 调用变量 p 的 distanceTo() 方法。
num distance = p.distanceTo(Point(4, 4));

使用 ?. 代替 . 可以避免因为左边表达式为 null 而导致的问题:

// If p is non-null, set its y value to 4.
// 如果 p 为非空则将其属性 y 的值设为 4
p?.y = 4;

使用构造函数 可以使用 构造函数 来创建一个对象。构造函数的命名方式可以为 类名 或 类名.标识符 的形式。例如下述代码分别使用 Point() 和 Point.fromJson() 两种构造器创建了 Point 对象:

var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});

以下代码具有相同的效果,但是构造函数名前面的的 new 关键字是可选的:

var p1 = new Point(2, 2);
var p2 = new Point.fromJson({'x': 1, 'y': 2});
从 Dart 2 开始,new 关键字是可选的。

获取对象的类型 可以使用 Object 对象的 runtimeType 属性在运行时获取一个对象的类型,该对象类型是 Type 的实例。

print('The type of a is ${a.runtimeType}');