Dart 语言基础入门篇

本文是【 从零开始学习,开发个Flutter App】路上的第 1 篇文章。

这篇文章介绍了 Dart 的基础特性,目的在于让你们创建对 Dart 语言的整体认知,初步掌握 Dart 的语法。node

咱们假定读者已经有必定的编程基础,若是你了解 JavaScript 或者 Java 等面向对象语言,那 Dart 学习起来应该颇有亲切感。web

Dart 是一门采起众家之长的编程语言。尽管 Dart 不少语法和 JavaScript 很类似,但 Dart 语言同时是一门强类型的语言,它同时结合了像 Java 这样强类型面向对象语言的特性,这使得它能胜任大型应用开发,同时它没有 Java 的臃肿,Dart 语言在设计上很是简洁、灵活和高效。express

JavaScript 从简单的浏览器脚本到服务端(nodejs),慢慢延伸到PC客户端(electron)、App (React Native)甚至小程序开发,它已然成为一门真正意义上的全栈开发语言。npm

若是说 JavaScript 是在漫长的时光里野蛮生长,那 Dart 从一开始就是精心设计出来的。若是说有一门语言取代JavaScript的位置,那极可能就是Dart。编程

Talk is cheep,下面就让咱们来亲自感觉一下这门语言的吧。小程序

变量

你能够像 JavaScript 那样声明一个变量:设计模式

var name = 'Bob';
复制代码

编译器会推导出 name 的类型是String 类型,等价于:数组

String name = 'Bob';
复制代码

咱们能够从下面代码窥见 Dart 是强类型语言的特性:浏览器

var name = 'Bob';
  
// 调用 String 的方法
print(name.toLowerCase());

// 编译错误
// name = 1;
复制代码

前面咱们说过,Dart 除了具有简洁的特色,并且也能够是很是灵活的,若是你想变换一个变量的类型,你也可使用dynamic 来声明变量,这就跟 JavaScript 同样了:缓存

dynamic name = 'Bob'; //String 类型
name = 1;// int 类型
print(name);
复制代码

上面的代码能够正常编译和运行,但除非你有足够的理由,请不要轻易使用。

final 的语义和 Java 的同样,表示该变量是不可变的:

// String 能够省略
final String name = 'Bob'; 

// 编译错误
// name = 'Mary';
复制代码

其中 String 能够省略,Dart 编译器足够聪明地知道变量name 的类型。

若是要声明常量,可使用const 关键词:

const PI = '3.14';

class Person{
  static const name = 'KK';
}

复制代码

若是类变量,则须要声明为static const

内置类型

不像Java把类型分的特别细,好比整数类型,就有byteshortintlong 。Dart 的类型设计至关简洁,这也是 Dart 容易上手的缘由之一,能够理解为经过牺牲空间来换取效率吧。

数值类型

Dart 内置支持两种数值类型,分别是intdouble ,它们的大小都是64位。

var x = 1;
// 0x开头为16进制整数
var hex = 0xDEADBEEF;


var y = 1.1;
// 指数形式
var exponents = 1.42e5;
复制代码

须要注意的是,在Dart中,全部变量值都是一个对象,intdouble类型也不例外,它们都是num类型的子类,这点和JavaJavaScript都不太同样:

// String -> int
var one = int.parse('1');
assert(one == 1);

// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);

// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');

// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');
复制代码

字符串

Dart 字符串使用的是UTF-16编码。

var s = '中';
s.codeUnits.forEach((ch) => print(ch));
// 输出为UNICODE值
20013
复制代码

Dart 采用了 JavaScript 中相似模板字符串的概念,能够在字符串经过${expression}语法插入变量:

var s = "hello";
  
print('${s}, world!');
  
//能够简化成:
print('$s, world!');

//调用方法
print('${s.toUpperCase()}, world!');
复制代码

Dart 能够直接经过==来比较字符串:

var s1 = "hello";
var s2 = "HELLO";
assert(s1.toUpperCase() == s2);
复制代码

布尔类型

Dart 布尔类型对应为bool关键词,它有truefalse两个值,这点和其余语言区别不大。值得一提的是,在Dart的条件语句ifassert表达式里面,它们的值必须是bool类型,这点和 JavaScript 不一样。

var s = '';
assert(s.isEmpty);

if(s.isNotEmpty){
// do something
}
  
//编译错误,在JavaScript经常使用来判断undefined
if(s){
}
复制代码

Lists

你能够把Dart中的List对应到 JavaScript 的数组或者 Java 中的ArrayList,但 Dart 的设计更为精巧。

你能够经过相似 JavaScript 同样声明一个数组对象:

var list = [];
list.add('Hello');
list.add(1);
复制代码

这里List容器接受的类型是dynamic,你能够往里面添加任何类型的对象,但若是像这样声明:

var iList = [1,2,3];
iList.add(4);
//编译错误 The argument type 'String' can't be assigned to the parameter type 'int'
//iList.add('Hello');
复制代码

那么Dart就会推导出这个List是个List<int>,今后这个List就只能接受int类型数据了,你也能够显式声明List的类型:

var sList = List<String>();

//在Flutter类库中,有许多这样的变量声明:
List<Widget> children = const <Widget>[];
复制代码

上面右边那个 const 的意思表示常量数组,在这里你能够理解为一个给children赋值了一个编译期常量空数组,这样的作法能够很好的节省内存,下面的例子可让你们更好的理解常量数组的概念:

var constList = const <int>[1,2];
constList[0] = 2; //编译经过, 运行错误
constList.add(3); //编译经过, 运行错误
复制代码

Dart2.3 增长了扩展运算符 (spread operator) ......?,经过下面的例子你很容易就明白它们的用法:

var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
复制代码

若是扩展对象多是null,可使用...?

var list;
 var list2 = [0, ...?list];
 assert(list2.length == 1);
复制代码

你能够直接在元素内进行判断,决定是否须要某个元素:

var promoActive = true;
var nav = [
    'Home',
    'Furniture',
    'Plants',
    promoActive? 'About':'Outlet'
];
复制代码

甚至使用for来动态添加多个元素:

var listOfInts = [1, 2, 3];
var listOfStrings = [
  '#0',
  for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');
复制代码

这种动态的能力使得 Flutter 在构建 Widget 树的时候很是方便。

Sets

Set的语意和其余语言的是同样的,都是表示在容器中对象惟一。在Dart中,Set默认是LinkedHashSet实现,表示元素按添加前后顺序排序。

声明Set对象:

var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
复制代码

遍历Set,遍历除了上面提到的for...in,你还可使用相似 Java 的 lambada 中的 forEach 形式:

halogens.add('bromine');
halogens.add('astatine');
halogens.forEach((el) => print(el));
复制代码

输出结果:

fluorine
chlorine
bromine
iodine
astatine
复制代码

除了容器的对象惟一特性以外,其余基本和List是差很少的。

// 添加类型声明:
var elements = <String>{};

var promoActive = true;
// 动态添加元素
final navSet = {'Home', 'Furniture', promoActive? 'About':'Outlet'};
复制代码

Maps

Map对象的声明方式保持了 JavaScript 的习惯,Dart 中Map的默认实现是LinkedHashMap,表示元素按添加前后顺序排序。

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

assert(gifts['first'] == 'partridge');
复制代码

添加一个键值对:

gifts['fourth'] = 'calling birds';
复制代码

遍历Map

gifts.forEach((key,value) => print('key: $key, value: $value'));
复制代码

函数

在 Dart 中,函数自己也是个对象,它对应的类型是Function,这意味着函数能够当作变量的值或者做为一个方法入传参数值。

void sayHello(var name){
  print('hello, $name');
}

void callHello(Function func, var name){
  func(name);
}

void main(){
  // 函数变量
  var helloFuc = sayHello;
  // 调用函数
  helloFuc('Girl');
  // 函数参数
  callHello(helloFuc,'Boy');
}
复制代码

输出:

hello, Girl
hello, Boy
复制代码

对于只有一个表达式的简单函数,你还能够经过=>让函数变得更加简洁,=> expr在这里至关于{ return expr; } ,咱们来看一下下面的语句:

String hello(var name ) => 'hello, $name';
复制代码

至关于:

String hello(var name ){
  return 'hello, $name';
}
复制代码

参数

在Flutter UI库里面,命名参数随处可见,下面是一个使用了命名参数(Named parameters)的例子:

void enableFlags({bool bold, bool hidden}) {...}
复制代码

调用这个函数:

enableFlags(bold: false);
enableFlags(hidden: false);
enableFlags(bold: true, hidden: false);
复制代码

命名参数默认是可选的,若是你须要表达该参数必传,可使用@required

void enableFlags({bool bold, @required bool hidden}) {}
复制代码

固然,Dart 对于通常的函数形式也是支持的:

void enableFlags(bool bold, bool hidden) {}
复制代码

和命名参数不同,这种形式的函数的参数默认是都是要传的:

enableFlags(false, true);
复制代码

你可使用[]来增长非必填参数:

void enableFlags(bool bold, bool hidden, [bool option]) {}
复制代码

另外,Dart 的函数还支持设置参数默认值:

void enableFlags({bool bold = false, bool hidden = false}) {...}

String say(String from, [String device = 'carrier pigeon', String mood]) {}
复制代码

匿名函数

顾名思意,匿名函数的意思就是指没有定义函数名的函数。你应该对此不陌生了,咱们在遍历ListMap的时候已经使用过了,经过匿名函数能够进一步精简代码:

var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
  print('${list.indexOf(item)}: $item');
});
复制代码

闭包

Dart支持闭包。没有接触过JavaScript的同窗可能对闭包(closure)比较陌生,这里给你们简单解释一下闭包。

闭包的定义比较拗口,咱们不去纠结它的具体定义,而是打算经过一个具体的例子去理解它:

Function closureFunc() {
  var name = "Flutter"; // name 是一个被 init 建立的局部变量
  void displayName() { // displayName() 是内部函数,一个闭包
    print(name); // 使用了父函数中声明的变量
  }
  return displayName;
}

void main(){
  //myFunc是一个displayName函数
  var myFunc = closureFunc(); //(1)
  
  // 执行displayName函数
  myFunc(); // (2)
}
复制代码

结果如咱们所料的那样打印了Flutter

在(1)执行完以后,name做为一个函数的局部变量,引用的对象不是应该被回收掉了吗?可是当咱们在内函数调用外部的name时,它依然能够神奇地被调用,这是为何呢?

这是由于Dart在运行内部函数时会造成闭包,闭包是由函数以及建立该函数的词法环境组合而成,这个环境包含了这个闭包建立时所能访问的全部局部变量

咱们简单变一下代码:

Function closureFunc() {
  var name = "Flutter"; // name 是一个被 init 建立的局部变量
  void displayName() { // displayName() 是内部函数,一个闭包
    print(name); // 使用了父函数中声明的变量
  }
  name = 'Dart'; //从新赋值
  return displayName;
}
复制代码

结果输出是Dart,能够看到内部函数访问外部函数的变量时,是在同一个词法环境中的。

返回值

在Dart中,全部的函数都必须有返回值,若是没有的话,那将自动返回null

foo() {}

assert(foo() == null);
复制代码

流程控制

这部分和大部分语言都同样,在这里简单过一下就行。

if-else

if(hasHause && hasCar){
    marry();
}else if(isHandsome){
    date();
}else{
    pass();
}
复制代码

循环

各类for:

var list = [1,2,3];

for(var i = 0; i != list.length; i++){}

for(var i in list){}
复制代码

while和循环中断(中断也是在for中适用的):

var i = 0;
  while(i != list.length){
    if(i % 2 == 0){
       continue;
    }
     print(list[i]);
  }

  i = 0;
  do{
    print(list[i]);
    if(i == 5){
      break;
    }
  }while(i != list.length);
复制代码

若是对象是Iterable类型,你还能够像Java的 lambada 表达式同样:

list.forEach((i) => print(i));
  
list.where((i) =>i % 2 == 0).forEach((i) => print(i));
复制代码

switch

switch能够用于intdoubleStringenum等类型,switch 只能在同类型对象中进行比较,进行比较的类不要覆盖==运算符。

var color = '';
  switch(color){
    case "RED":
      break;
    case "BLUE":
      break;
    default:
      
  }
复制代码

assert

在Dart中,assert语句常常用来检查参数,它的完整表示是:assert(condition, optionalMessage),若是conditionfalse,那么将会抛出[AssertionError]异常,中止执行程序。

assert(text != null);

assert(urlString.startsWith('https'), 'URL ($urlString) should start with "https".');
复制代码

assert 一般只用于开发阶段,它在产品运行环境中一般会被忽略。在下面的场景中会打开assert

  1. Flutter 的 debug mode
  2. 一些开发工具好比dartdevc默认会开启。
  3. 一些工具,像dartdart2js ,能够经过参数--enable-asserts 开启。

异常处理

Dart 的异常处理和Java很像,可是Dart中全部的异常都是非检查型异常(unchecked exception),也就是说,你没必要像 Java 同样,被强制须要处理异常。

Dart 提供了ExceptionError 两种类型的异常。 通常状况下,你不该该对Error类型错误进行捕获处理,而是尽可能避免出现这类错误。

好比OutOfMemoryErrorStackOverflowErrorNoSuchMethodError等都属于Error类型错误。

前面提到,由于 Dart 不像 Java 那样能够声明编译期异常,这种作法可让代码变得更简洁,可是容易忽略掉异常的处理,因此咱们在编码的时候,在可能会有异常的地方要注意阅读API文档,另外本身写的方法,若是有异常抛出,要在注释处进行声明。好比类库中的File类其中一个方法注释:

/** * Synchronously read the entire file contents as a list of bytes. * * Throws a [FileSystemException] if the operation fails. */
  Uint8List readAsBytesSync();
复制代码

抛出异常

throw FormatException('Expected at least 1 section');
复制代码

throw除了能够抛出异常对象,它还能够抛出任意类型对象,但建议仍是使用标准的异常类做为最佳实践。

throw 'Out of llamas!';
复制代码

捕获异常

能够经过on 关键词来指定异常类型:

var file = File("1.txt");
  try{
    file.readAsStringSync();
  } on FileSystemException {
     //do something
  }
复制代码

使用catch关键词获取异常对象,catch有两个参数,第一个是异常对象,第二个是错误堆栈。

try{
    file.readAsStringSync();
} on FileSystemException catch (e){
    print('exception: $e');
} catch(e, s){ //其他类型
   print('Exception details:\n $e');
   print('Stack trace:\n $s');
}
复制代码

使用rethrow 抛给上一级处理:

try{
    file.readAsStringSync();
  } on FileSystemException catch (e){
    print('exception: $e');
  } catch(e){
     rethrow;
  }
复制代码

finally

finally通常用于释放资源等一些操做,它表示最后必定会执行的意思,即使try...catch中有return,它里面的代码也会承诺执行。

try{
     print('hello');
     return;
  } catch(e){
     rethrow;
  } finally{
     print('finally');
}
复制代码

输出:

hello
finally
复制代码

Dart 是一门面向对象的编程语言,全部对象都是某个类的实例,全部类继承了Object类。

一个简单的类:

class Point {
  num x, y;

  // 构造器
  Point(this.x, this.y);
  
  // 实例方法
  num distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    return sqrt(dx * dx + dy * dy);
  }
}
复制代码

类成员

Dart 经过. 来调用类成员变量和方法的。

//建立对象,new 关键字能够省略
var p = Point(2, 2);

// Set the value of the instance variable y.
p.y = 3;

// Get the value of y.
assert(p.y == 3);

// Invoke distanceTo() on p.
num distance = p.distanceTo(Point(4, 4));
复制代码

你还能够经过.?来避免null对象。在Java 里面,常常须要大量的空判断来避免NullPonterException,这是让人诟病Java的其中一个地方。而在Dart中,能够很方便地避免这个问题:

// If p is non-null, set its y value to 4.
p?.y = 4;
复制代码

在 Dart 中,没有privateprotectedpublic这些关键词,若是要声明一个变量是私有的,则在变量名前添加下划线_,声明了私有的变量,只在本类库中可见。

class Point{
  num _x;
  num _y;
}
复制代码

构造器(Constructor)

若是没有声明构造器,Dart 会给类生成一个默认的无参构造器,声明一个带参数的构造器,你能够像 Java这样:

class Person{
  String name;
  int sex;
  
  Person(String name, int sex){
    this.name = name;
    this.sex = sex;
  }
}
复制代码

也可使用简化版:

Person(this.name, this.sex);
复制代码

或者命名式构造器:

Person.badGirl(){
    this.name = 'Bad Girl';
    this.sex = 1;
}
复制代码

你还能够经过factory关键词来建立实例:

Person.goodGirl(){
	this.name = 'good Girl';
	this.sex = 1;
}

factory Person(int type){
	return type == 1 ? Person.badGirl(): Person.goodGirl();
}
复制代码

factory对应到设计模式中工厂模式的语言级实现,在 Flutter 的类库中有大量的应用,好比Map

// 部分代码
abstract class Map<K, V> {  
	factory Map.from(Map other) = LinkedHashMap<K, V>.from;
}
复制代码

若是一个对象的建立过程比较复杂,好比须要选择不一样的子类实现或则须要缓存实例等,你就能够考虑经过这种方法。在上面Map例子中,经过声明 factory来选择了建立子类LinkedHashMapLinkedHashMap.from也是一个factory,里面是具体的建立过程)。

若是你想在对象建立以前的时候还想作点什么,好比参数校验,你能够经过下面的方法:

Person(this.name, this.sex): assert(sex == 1)
复制代码

在构造器后面添加的一些简单操做叫作initializer list

在Dart中,初始化的顺序以下:

  1. 执行initializer list;
  2. 执行父类的构造器;
  3. 执行子类的构造器。
class Person{
  String name;
  int sex;

  Person(this.sex): name = 'a', assert(sex == 1){
    this.name = 'b';
    print('Person');
  }

}

class Man extends Person{
   Man(): super(1){
     this.name = 'c';
     print('Man');
   }
}

void main(){
  Person person = Man();
  print('name : ${person.name}');
}
复制代码

上面的代码输出为:

Person
Man
name : c
复制代码

若是子类构造器没有显式调用父类构造器,那么默认会调用父类的默认无参构造器。显式调用父类的构造器:

Man(height): this.height = height, super(1);
复制代码

重定向构造器:

Man(this.height, this.age): assert(height > 0), assert(age > 0);

Man.old(): this(12, 60); //调用上面的构造器
复制代码

Getter 和 Setter

在 Dart 中,对 GetterSetter 方法有专门的优化。即使没有声明,每一个类变量也会默认有一个get方法,在隐含接口章节会有体现。

class Rectangle {
  num left, top, width, height;

  Rectangle(this.left, this.top, this.width, this.height);

  num get right => left + width;
  set right(num value) => left = value - width;
  num get bottom => top + height;
  set bottom(num value) => top = value - height;
}

void main() {
  var rect = Rectangle(3, 4, 20, 15);
  assert(rect.left == 3);
  rect.right = 12;
  assert(rect.left == -8);
}
复制代码

抽象类

Dart 的抽象类和Java差很少,除了不能够实例化,能够声明抽象方法以外,和通常类没有区别。

abstract class AbstractContainer {
  num _width;

  void updateChildren(); // 抽象方法,强制继承子类实现该方法。

  get width => this._width;
  
  int sqrt(){
    return _width * _width;
  }
}
复制代码

隐含接口

Dart 中的每一个类都隐含了定义了一个接口,这个接口包含了这个类的全部成员变量和方法,你能够经过implements关键词来从新实现相关的接口方法:

class Person {
  //隐含了 get 方法
  final _name;

  Person(this._name);

  String greet(String who) => 'Hello, $who. I am $_name.';
}

class Impostor implements Person {
  // 须要从新实现
  get _name => '';

  // 须要从新实现
  String greet(String who) => 'Hi $who. Do you know who I am?';
}
复制代码

实现多个接口:

class Point implements Comparable, Location {...}
复制代码

继承

和Java基本一致,继承使用extends关键词:

class Television {
  void turnOn() {
    doSomthing();
  }
}

class SmartTelevision extends Television {

  @override
  void turnOn() {
    super.turnOn(); //调用父类方法
    doMore();
  }
}
复制代码

重载操做符

比较特别的是,Dart 还容许重载操做符,好比List类支持的下标访问元素,就定义了相关的接口:

E operator [](int index);
复制代码

咱们经过下面的实例来进一步说明重载操做符:

class MyList{

  var list = [1,2,3];

  operator [](int index){
    return list[index];
  }
}

void main() {
  var list = MyList();
  print(list[1]); //输出 2
}
复制代码

扩展方法

这个特性也是Dart让人眼前一亮的地方(Dart2.7以后才支持),能够对标到 JavaScript 中的 prototype。经过这个特性,你甚至能够给类库添加新的方法:

//经过关键词 extension 给 String 类添加新方法
extension NumberParsing on String {
  int parseInt() {
    return int.parse(this);
  }
}
复制代码

后面String对象就能够调用该方法了:

print('42'.parseInt()); 
复制代码

枚举类型

枚举类型和保持和Java的关键词一致:

enum Color { red, green, blue }
复制代码

switch中使用:

// color 是 enmu Color 类型
switch(color){
    case Color.red:
      break;
    case Color.blue:
      break;
    case Color.green:
      break;
    default:
      break;
}
复制代码

枚举类型还有一个index的getter,它是个连续的数字序列,从0开始:

assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
复制代码

新特性:Mixins

这个特性进一步加强了代码复用的能力,若是你有写过Android的布局XML代码或者Freemaker模板的话,那这个特性就能够理解为其中inlclude 的功能。

声明一个mixin类:

mixin Musical {
  bool canPlayPiano = false;
  bool canCompose = false;
  bool canConduct = false;

  void entertainMe() {
    if (canPlayPiano) {
      print('Playing piano');
    } else if (canConduct) {
      print('Waving hands');
    } else {
      print('Humming to self');
    }
  }
}
复制代码

经过with关键词进行复用:

class Musician extends Performer with Musical {
  // ···
}

class Maestro extends Person with Musical, Aggressive, Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true;
  }
}
复制代码

mixin类甚至能够经过on关键词实现继承的功能:

mixin MusicalPerformer on Musician {
  // ···
}
复制代码

类变量和类方法

class Queue {
  //类变量
  static int maxLength = 1000;
  // 类常量
  static const initialCapacity = 16;
  // 类方法
  static void modifyMax(int max){
    _maxLength = max;
  }
}

void main() {
  print(Queue.initialCapacity);
  Queue.modifyMax(2);
  print(Queue._maxLength);
}
复制代码

泛型

在面向对象的语言中,泛型主要的做用有两点:

一、类型安全检查,把错误扼杀在编译期:

var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
//编译错误
names.add(42); 
复制代码

二、加强代码复用,好比下面的代码:

abstract class ObjectCache {
  Object getByKey(String key);
  void setByKey(String key, Object value);
}

abstract class StringCache {
  String getByKey(String key);
  void setByKey(String key, String value);
}
复制代码

你能够经过泛型把它们合并成一个类:

abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}
复制代码

在Java中,泛型是经过类型擦除来实现的,但在Dart中实打实的泛型:

var names = <String>[];
 names.addAll(['Tom',"Cat"]);
 // is 能够用于类型判断
 print(names is List<String>); // true
 print(names is List); // true
 print(names is List<int>); //false
复制代码

你能够经过extends关键词来限制泛型类型,这点和Java同样:

abstract class Animal{}
class Cat extends Animal{}
class Ext<T extends Animal>{
  T data;
}

void main() {
  var e = Ext(); // ok
  var e1 = Ext<Animal>(); // ok
  var e2 = Ext<Cat>(); // ok
  var e3 = Ext<int>(); // compile error
}
复制代码

使用类库

有生命力的编程语言,它背后都有一个强大的类库,它们可让咱们站在巨人的肩膀上,又免于从新造轮子。

导入类库

在Dart里面,经过import关键词来导入类库。

内置的类库使用dart:开头引入:

import 'dart:io';
复制代码

了解更多内置的类库能够查看这里

第三方类库或者本地的dart文件用package:开头:

好比导入用于网络请求的dio库:

import 'package:dio/dio.dart';
复制代码

Dart 应用自己就是一个库,好比个人应用名是ccsys,导入其余文件夹的类:

import 'package:ccsys/common/net_utils.dart';
import 'package:ccsys/model/user.dart';
复制代码

若是你使用IDE来开发,通常这个事情不用你来操心,它会自动帮你导入的。

Dart 经过pub.dev来管理类库,相似Java世界的Maven 或者Node.js的npm同样,你能够在里面找到很是多实用的库。

解决类名冲突

若是导入的类库有类名冲突,能够经过as使用别名来避免这个问题:

import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;

// 使用来自 lib1 的 Element
Element element1 = Element();

// 使用来自 lib2 的 Element
lib2.Element element2 = lib2.Element();

复制代码

导入部分类

在一个dart文件中,可能会存在不少个类,若是你只想引用其中几个,你能够增长show或者hide来处理:

//文件:my_lib.dart
class One {}

class Two{}

class Three{}
复制代码

使用show导入OneTwo类:

//文件:test.dart
import 'my_lib.dart' show One, Two;

void main() {
  var one = One();
  var two = Two();
  //compile error
  var three = Three();
}
复制代码

也可使用hide排除Three,和上面是等价的:

//文件:test.dart
import 'my_lib.dart' hide Three;

void main() {
  var one = One();
  var two = Two();
}
复制代码

延迟加载库

目前只有在web app(dart2js)中才支持延迟加载,Flutter、Dart VM是不支持的,咱们这里仅作一下简单介绍。

你须要经过deferred as来声明延迟加载该类库:

import 'package:greetings/hello.dart' deferred as hello;
复制代码

当你须要使用的时候,经过loadLibrary()加载:

Future greet() async {
  await hello.loadLibrary();
  hello.printGreeting();
}
复制代码

你能够屡次调用loadLibrary,它不会被重复加载。

异步支持

这个话题稍微复杂,咱们将用另一篇文章独立讨论这个问题,请留意下一篇内容。

参考资料

  1. 学习Dart的十大理由

  2. A tour of the Dart language

  3. Dart 常量构造器的理解

  4. JavaScript 闭包

关于AgileStudio

咱们是一支由资深独立开发者和设计师组成的团队,成员均有扎实的技术实力和多年的产品设计开发经验,提供可信赖的软件定制服务。

相关文章
相关标签/搜索