Flutter日渐火爆,所以在进行Flutter学习前先学习一些其所使用的开发语言dart的基础,这篇文章主要学习了html
// 定义一个方法。 printInteger(int aNumber) { print('The number is $aNumber.'); // Print to console. } // main入口函数。 main() { var number = 42; // 声明并初始化变量。 printInteger(number); // 函数调用。 } 复制代码
dart注释方法,更多注释能够看个人另外一篇文章https://www.jianshu.com/p/d1dae0d5c472java
数据类型,更多数据类型可看https://www.dartlang.org/guides/language/language-tour#built-in-types程序员
一种方便的显示输出方式express
字符串,dart中更推荐使用**'...'**编程
字符串插值:包括字符串文字内部的变量或表达式的字符串api
一种声明变量而不指定其类型的方法,关键字之一缓存
当要学习dart时,请记住如下事实和概念:bash
一切皆为对象,放在变量中的全部内容都是一个对象,每一个对象都是一个class的实例,numbers,函数和null都是对象,全部对象都继承自Object类。下面给个图你看一下,没错,连int都是对象: markdown
尽管Dart是强类型的,但类型注释是可选的,由于Dart能够推断类型。在上面的代码中,数字被推断为int类型。若是要明确说明不须要任何类型,请使用特殊类型dynamic。异步
Dart支持泛型类型,如List(整数列表)或List(任何类型的对象列表)。
Dart支持顶级函数(例如main()),以及绑定到类或对象的函数(分别是静态和实例方法),还能够在函数内建立函数(嵌套函数或本地函数)。
Dart也支持顶级变量,以及绑定到类或对象的变量(静态和实例变量),实例变量有时称为字段或属性。
与Java不一样,Dart没有关键字public,protected和private,若是标识符如下划线(_)开头,则它表明是私有的,不然都为公有。
标识符能够以字母或下划线(_)开头,后跟这些字符加数字的任意组合。
Dart有表达式(具备运行时值)和语句(不具备运行时值)。例如,条件表达式"条件? expr1:expr2的值为expr1或expr2"。将其与if-else语句进行比较,该语句没有任何值。语句一般包含一个或多个表达式,但表达式不能直接包含语句。
dart共有60个关键字,因此如下篇幅可能有点长
abstract2 | dynamic2 | implements2 | show1 |
as2 | else | import2 | static2 |
assert | enum | in | super |
async1 | export2 | in2 | super |
await3 | extends | is | sync1 |
break | external2 | library2 | this |
case | factory2 | mixin2 | throw |
catch | false | new | true |
class | final | null | try |
const | finally | on1 | typedef2 |
continue | for | operator2 | var |
covariant2 | Function2 | part2 | void |
default | get2 | rethrow | while |
deferred2 | hide1 | return | with |
do | if | set2 | yield3 |
详细可看下面说明
使用abstract修饰符定义抽象类即没法实例化的类,抽象类能够自定义一些接口。抽象类一般有抽象方法,下面是一个声明具备抽象方法的抽象类的示例:
// 该类声明为抽象类且不可实例化。
abstract class AbstractContainer {
// 定义构造函数,变量,方法等...
// 其余....
// 抽象方法。
void updateChildren();
}
复制代码
下面为实现抽象方法的例子:
//抽象类 abstract class Doer { void doSomething(); // 定义一个抽象方法 } //继承抽象类实现抽象方法 class EffectiveDoer extends Doer { void doSomething() { // 实现逻辑 } } 复制代码
顾名思义,dynamic(动态), 直接先上代码
void judge(dynamic arg){ if (arg is bool){ print('arg is bool'); } else if (arg is String){ print('arg is String'); } else if (arg is int){ print('arg is int'); } else { print('arg is others'); } } 复制代码
dynamic同等于Object, 即上面代码能够等同于下面代码:
void judge(Object arg){ if (arg is bool){ print('arg is bool'); } else if (arg is String){ print('arg is String'); } else if (arg is int){ print('arg is int'); } else { print('arg is others'); } } 复制代码
在Dart中,dynamic和Object可表示全部类型, 这二者区别是使用dynamic能够处理更复杂的不肯定类型,例如超出了Dart的类型系统,或者值来自互操做或者在静态类型系统范围以外的状况。
Java中,该关键字用于实现接口类(interface), Dart中亦有相同的意思,实现接口,咱们先看代码:
// Person类,包含方法greet(). class Person { //在该类中,属于私有,仅对当前类可见 final _name; // 不是接口,只是构造函数 Person(this._name); // 接口 String greet(String who) => 'Hello, $who. I am $_name.'; } // 实现Person类接口的类 class Impostor implements Person { //只是一个普通的get方法,可忽略 get _name => ''; //实现Person的greet方法 String greet(String who) => 'Hi $who. Do you know who I am?'; } //只是一个测试方法 String greetBob(Person person) => person.greet('Bob'); void main() { print(greetBob(Person('Kathy'))); //打印 -> Hello, Bob. I am Kathy. print(greetBob(Impostor())); //打印 -> Hi Bob. Do you know who I am? } 复制代码
Dart中没有Java的interface功能,若是Impostor在不继承Person类的状况想实现Person类的接口的话,可使用implements关键字。implements可同时实现多个类的接口:
class Point implements Comparable, Location {...}
复制代码
有时候咱们导入一个库,若是只想使用库的一部分,则能够有选择地导入库,例如:
// 只导入foo import 'package:lib1/lib1.dart' show foo; 复制代码
//导入整个库除了foo import 'package:lib2/lib2.dart' hide foo; 复制代码
as,is,和 !is 运算符在运行时检查类型很方便
代码示例:
if (emp is Person) { // 类型检查 emp.firstName = 'Bob'; } 复制代码
// 若是emp为Person,则将firstName改成Bod, 不然会在运行时期报错 (emp as Person).firstName = 'Bob'; 复制代码
若是导入两个具备冲突标识符(class)的库,则能够为一个或两个库指定前缀。 例如,若是library1和library2都有一个Element类,那么as能够这样使用:
import 'package:lib1/lib1.dart'; import 'package:lib2/lib2.dart' as lib2; //指定库的前缀为lib2 // Uses Element from lib1. Element element1 = Element(); // Uses Element from lib2. lib2.Element element2 = lib2.Element(); 复制代码
与Java或其余语言同样,Dart支持带有可选else语句的if语句:
if (isRaining()) { you.bringRainCoat(); } else if (isSnowing()) { you.wearJacket(); } else { car.putTopDown(); } 复制代码
与Java同样,使用import导入其余包。例如,Dart Web应用程序一般使用dart:html库,能够这样导入:
import 'dart:html'; 复制代码
若是只是想导入某个包下的某个dart文件,能够这样导入:
import 'package:test/test.dart'; //指定导入test.dart(相似于Java中的test.java) 复制代码
使用static关键字实现类范围的变量和方法
static变量(只有在使用的时候才会进行初始化):
class Queue { static const initialCapacity = 16; // ··· } void main() { assert(Queue.initialCapacity == 16); } 复制代码
static方法:
import 'dart:math'; class Point { num x, y; Point(this.x, this.y); static num distanceBetween(Point a, Point b) { var dx = a.x - b.x; var dy = a.y - b.y; return sqrt(dx * dx + dy * dy); } } void main() { var a = Point(2, 2); var b = Point(4, 4); var distance = Point.distanceBetween(a, b); //静态方法,不用实例化 assert(2.8 < distance && distance < 2.9); print(distance); } 复制代码
断言assert(条件); 若是条件为返回false,使用assert语句能够中断正常执行, 代码:
// text等于null时中断 assert(text != null); // number > 100时中断 assert(number < 100); // 若是urlString不是以"https"开头 assert(urlString.startsWith('https')); 复制代码
若是要附加一个消息到断言,可在第二个参数输入一个字符串:
assert(urlString.startsWith('https'), 'URL ($urlString) should start with "https".'); 复制代码
枚举类型(一般称为枚举或枚举)是一种特殊类型,用于表示固定数量的常量值。 使用enum关键字声明枚举类型, 例如:
enum Color { red, green, blue }
复制代码
枚举中的每一个值都有一个索引getter,它返回枚举声明中值的从零开始的位置。 例如,第一个值具备索引0,第二个值具备索引1:
print('red index: \${Color.red.index}'); // -> 打印red index: 0 print('green index: \${Color.green.index}'); // -> 打印: green index: 1 print('blue index: \${Color.blue.index}');· //-> 打印: blue index: 2 复制代码
要获取枚举中全部值的列表,可使用如下方法:
List<Color> colors = Color.values;
复制代码
您能够在switch语句中使用枚举,若是您不处理全部枚举值,您将收到警告:
var aColor = Color.blue; switch (aColor) { case Color.red: print('Red as roses!'); break; case Color.green: print('Green as grass!'); break; default: // 没有这行代码的话,会有一个警告 print(aColor); // 'Color.blue' } 复制代码
枚举类型具备如下限制:
1.不能子类化,混合或实现枚举。 2.没法显式实例化枚举。
可使用标准for循环进行迭代, 例如:
var message = StringBuffer('Dart is fun'); for (var i = 0; i < 5; i++) { message.write('!'); } 复制代码
像List和Set这样的可迭代类支持使用的for-in形式迭代:
var list = [0, 1, 2]; for (var x in list) { print(x); // 0 1 2 } 复制代码
等同于:
for (int i = 0; i < list.length; i++){ print(list[i]); // 0 1 2 } 复制代码
使用extends来继承一个类,使用super来调用父类:
class Television { void turnOn() { _illuminateDisplay(); _activateIrSensor(); } // ··· } class SmartTelevision extends Television { void turnOn() { super.turnOn(); //调用父类方法 _bootNetworkInterface(); _initializeMemory(); _upgradeApps(); } // ··· } 复制代码
Dart库中包含许多返回Future或Stream对象的函数,关于Future和Steam会在后续进行讲解,这里暂不深究。 这些函数是异步的:它们在设置可能耗时的操做(例如I/O)后返回,而不等待该操做完成。
async和await关键字用于异步编程
async关键字修饰一个方法,要求必须返回一个Future对象,下面为代码例子:
//async关键字声明该函数内部有代码须要延迟执行 Future<String> getResult() async { return await getResultFromDb(); //await关键字声明运算为延迟执行,而后返回运算结果 } Future<String> getResultFromDb() { // 不少延时操做 // 不少延时操做 // 不少延时操做 // 不少延时操做 return new Future((){ return 'This is server...'; }); } //打印:result = This is server... print(getResult().then((result){ print('result = $result'); })); 复制代码
咱们来看一个官方的http库的代码: http: ^0.12.0
export 'src/base_client.dart'; export 'src/base_request.dart'; export 'src/base_response.dart'; export 'src/byte_stream.dart'; export 'src/client.dart'; export 'src/exception.dart'; export 'src/multipart_file.dart'; export 'src/multipart_request.dart'; export 'src/request.dart'; export 'src/response.dart'; export 'src/streamed_request.dart'; export 'src/streamed_response.dart'; 复制代码
能够看到export了几个文件,即导出了这几个文件,使外部这几个文件的api,这时咱们导入http来使用一下:
import 'package:http/http.dart' as http; 复制代码
能够看到导入的几个文件的类均可用了,那咱们再找一个没export的文件来看看外部是否可用,咱们拿browser_client.dart来看看,其中有一个类:
咱们在外部使用的时候:
是会报错的,由于该类并无export,即外部不可以使用。
已移除
Dart中的switch语句可以使用整数,字符串或编译时常量, 如下为使用字符串代码示例:
var command = 'OPEN'; switch (command) { case 'CLOSED': executeClosed(); break; case 'PENDING': executePending(); break; case 'APPROVED': executeApproved(); break; case 'DENIED': executeDenied(); break; case 'OPEN': executeOpen(); break; default: //表示其余值的条件 executeUnknown(); } 复制代码
当咱们须要懒惰地(不须要不少手动定义可迭代类时复杂的公式化代码)生成一系列值时,能够考虑使用生成器函数, Dart内置支持两种生成器函数:
同步生成器:将函数体标记为sync *,并使用yield语句来赋值,下面例子为返回 0-n 的迭代器:
Iterable<int> naturalsTo(int n) sync* { print('start'); int k = 0; while (k < n) yield k++; print('end'); } //使用 void main() { var it = naturalsTo(5).iterator; while(it.moveNext()) { print(it.current); } } //打印 start value = 0 value = 1 value = 2 value = 3 value = 4 end 复制代码
调用方法naturalsTo时,会立刻返回Iterable,且能够获取迭代器iterator,可是,在调用遍历以前,naturalsTo函数主体并不会当即执行,这里咱们能够看到调用var it = naturalsTo(5).iterator的时候没有任何打印,而且咱们能够看到,在遍历打印的时候,先调用start,当把全部值打印完了,再打印end。说明调用naturalsTo获得这个Iterable的iterator的时候,yield会在你每次调用moveNext进行遍历的时候产生一个值。当函数运行到yield的时候,yield这里声明一个求值表达式,返回值后,函数会在下一次moveNext的时候继续执行函数体。
异步生成器函数,将函数体标记为async *,并使用yield语句来传递值:
Stream<int> asynchronousNaturalsTo(int n) async* { int k = 0; while (k < n) yield k++; } //使用 void main() { asynchronousNaturalsTo(5).listen((v) { print(v); }); } //打印 start 0 1 2 3 4 end 复制代码
使用异步生成器返回数据流string,和sync*同样,调用asynchronousNaturalsTo会当即返回Stream,可是只有在listen监听数据流的时候才会调用asynchronousNaturalsTo函数体,而且经过yield声明求值表达式来计算对应的值。
若是生成器内部使用递归的话,可使用yield *来提升其性能:
Iterable<int> naturalsDownFrom(int n) sync* { if (n > 0) { yield n; yield* naturalsDownFrom(n - 1); } } //使用 void main() { print(naturalsDownFrom(5)); } //打印 (5, 4, 3, 2, 1) 复制代码
naturalsDownFrom函数仍是返回一个Iterable,当参数为5时,5 > 0时,先执行yield 5, 这时迭代器首先会产生一个值5,而后再经过yield*生成新的值,而且加到当前迭代器中。
跳出循环
while (true) { if (shutDownRequested()) break; processIncomingRequests(); } 复制代码
跳到下一个循环迭代
or (int i = 0; i < candidates.length; i++) { var candidate = candidates[i]; if (candidate.yearsExperience < 5) { continue; } candidate.interview(); } 复制代码
表示代码的实现由外部提供,咱们定义一个类:
class Object { const Object(); external bool operator ==(other); external int get hashCode; external String toString(); } //使用 void main() { Object object = new Object(); print('to string = ${object.toString()}'); } //打印 to string = null //可是若是咱们将toString去掉的话,则会打印 to string = Instance of 'Object' //dart中默认的toString打印 复制代码
external声明了这些方法须要由外部去实现,若外部没实现,则会返回null
使用library关键字能够定义一个库的名字,咱们这里自定义一个库来讲明一下这两个关键字:
library main; //定义当前库的名字为main import 'dart:math' as math; //声明如下两个文件属于main库 part 'test/lib/liba.dart'; part 'test/lib/libb.dart'; class LibMain{ static int max(int a, int b) => math.max(a, b); static String getParts() => LibA.TAG + ", " + LibB.TAG; } 复制代码
liba.dart
part of main; //声明属于main库 class LibA{ static String TAG = 'liba'; } 复制代码
libb.dart
part of main; //声明属于main库 class LibB{ static String TAG = 'libb'; } 复制代码
再导入main以后,
import 'lib/main.dart'; 复制代码
liba.dart和libb.dart中声明的类外部可用:
part能够将库拆分为多个Dart文件,可是建议尽可能避免使用其来建立库,由于这样会使代码很难阅读和修改。建议直接直接在lib/<包名> .dart下建立一个“main”库文件,用一个main文件来管理全部公共API。
和Java中this相相似,用this关键字来引用当前实例
用来修饰构造函数,描述该构造函数做为一个工厂构造函数功能,在实现不用老是建立新实例的构造函数的时候,可使用factory关键字,例以下面例子中,可能从缓存中返回实例,或者子类的实例。
class Logger { final String name; bool mute = false; //一个维护Logger类的map static final Map<String, Logger> _cache = <String, Logger>{}; //根据不一样的name获取对应的Logger, factory Logger(String name) { if (_cache.containsKey(name)) { return _cache[name]; } else { final logger = Logger._internal(name); _cache[name] = logger; return logger; } } //一个内部构造函数 Logger._internal(this.name); void log(String msg) { if (!mute) print(msg); } } 复制代码
注意,使用factory修饰的构造函数不能使用this,相似于在Java的static函数中,不能使用this
Dart 2.1中引入了对mixin关键字的支持, 咱们能够看到官方的描述:Mixins是一种在多个类层次结构中重用类代码的方法。关键信息:
我这里只简单描述下该关键字的做用和使用方法:
//程序员喜欢写代码 class Programmer{ code(){ print('I am a programmer, i like coding.'); } } //歌唱家喜欢唱歌 class Singer{ singing(){ print('I am a singer, i like singing.'); } } //既爱编码,也爱唱歌 class Mixin with Programmer, Singer{ } void main() { Mixin mixin = Mixin(); mixin.code(); mixin.singing(); } //打印: I am a programmer, i like coding. I am a musician, i like singing. 复制代码
注意:这里类Programmer和Singer不能声明构造函数包括命名函数:
当咱们使用mixin调用不一样类相同接口结果会是怎样呢,咱们看下面代码:
class A { name(){ print('I am a student.'); } } class B{ name(){ print('I am a teacher.'); } } class AB with A, B{ } class BA with B, A{ } void main() { new AB().name(); new BA().name(); } //打印: I am a teacher. I am a student. 复制代码
能够看到接口相同的状况这里是name,最终会调用with的最后一个类的接口。
若是咱们须要限定,什么类才能被混入,可使用mixin+on的方法限定:
//mixn定义了类Flutter要求只有实现Programmer类的才能被混入 mixin Flutter on Programmer{ flu(){ print('This is in flutter.'); } } //会以下面图片报错 //class A with Flutter{ //} //能够混入 class B extends Programmer with Flutter{ } new B ().flu(); //打印This is in flutter. 复制代码
最后,关于mixin更详细的解释能够参考:
抛出异常:
throw FormatException('Expected at least 1 section'); 复制代码
也能够抛出任何任意对象异常:
throw 'Out of llamas!'; 复制代码
class Throw{ @override String toString() { return 'Are you ok?'; } } void main() { throw new Throw(); } 复制代码
异常捕获:
//普通使用 void main() { try{ throw "You are wrong."; }catch (e){ print('catch exception: '+e); } } //打印: catch exception: You are wrong. 复制代码
使用on能够捕获某种异常
class ExceptionA{ @override String toString() { return 'This is exception a.'; } } class ExceptionB{ @override String toString() { return 'This is exception b.'; } } throwCatchException(Object object){ try{ throw object; } on ExceptionA{ //指定某种异常类 print("It's exception a."); } on ExceptionB catch(e){ //指定某种异常类并获取异常对象 print(e); } on Exception catch (e){ print(e); } } void main() { throwCatchException(new ExceptionA()); throwCatchException(new ExceptionB()); throwCatchException(new Exception('')); } //打印: It's exception a. This is exception b. Exception: 复制代码
能够为catch()指定一个或两个参数, 第一个是抛出的异常对象,第二个是堆栈跟踪(StackTrace对象):
void main() { try{ throw 'This is a exception.'; }catch (e, s){ print('e ${e}'); print('s ${s}'); } } //打印: e This is a exception. s #0 main (file:///E:/flutter/projects/flutter/test/test.dart:5:5) #1 _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:289:19) #2 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12) 复制代码
若是想异常可传播, 使用rethrow接口
void misbehave() { try { dynamic foo = true; print(foo++); // 运行时出错 } catch (e) { print('misbehave() partially handled ${e.runtimeType}.'); rethrow; //容许调用者能够看到异常 } } void main() { try { misbehave(); } catch (e) { print('main() finished handling ${e.runtimeType}.'); } } //打印: misbehave() partially handled NoSuchMethodError. main() finished handling NoSuchMethodError. 复制代码
不管是否抛出异常,要确保某些代码运行,请使用finally子句。 若是没有catch子句与异常匹配,则在finally子句运行后抛出异常:
class ExceptionA{ @override String toString() { return 'This is exception a.'; } } class ExceptionB{ @override String toString() { return 'This is exception b.'; } } finallyMethod(){ print('finally method.'); } void main() { try { throw new ExceptionA(); } on ExceptionB catch (e) { print(e); } finally{ finallyMethod(); } } //打印: finally method. Unhandled exception: This is exception a. #0 main (file:///E:/flutter/projects/flutter/test/test.dart:21:5) #1 _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:289:19) #2 _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12) 复制代码
为了表示布尔值,Dart有一个名为bool的类型, 只有两个对象具备bool类型: true和false,它们都是编译时常量
建立类实例
声明一个类
final声明一个变量只能初始化一次,和java用法相同
const声明一个是编译时常量的变量, 常量变量不能进行赋值,若是const变量在类级别,则将其标记为static const。 当咱们想让一个变量不被改变,能够声明为const变量。
typedef用于给函数类型指定名称,由于在Dart中,函数也是一个对象,一般用Function泛指全部函数,咱们来看一下下面的例子(没有使用函数别名):
class SortedCollection { Function compare; //这里须要传递一个返回值为int,参数为(Object, Object)的函数 SortedCollection(int f(Object a, Object b)) { compare = f; } } //一个返回值为int,参数为(Object, Object)的函数 int sort(Object a, Object b) => 0; void main() { SortedCollection coll = SortedCollection(sort); // 咱们都知道compare是一个函数 // 可是咱们知道它是什么类型的函数吗,意味着咱们只知道它是一个函数,可是是什么类型的函数咱们不知道 assert(coll.compare is Function); // 这里毫无疑问是true, 即不会中断执行 } 复制代码
咱们能够用typedef来声明一个函数类型:
//定义一个函数类型为compare,其类型为 typedef Compare = int Function(Object a, Object b); class SortedCollection { Compare compare; SortedCollection(this.compare); } //一个返回值为int,参数为(Object, Object)的函数即类型为Compare的函数 int sort(Object a, Object b) => 0; void main() { SortedCollection coll = SortedCollection(sort); assert(coll.compare is Function); //True assert(coll.compare is Compare); //True } 复制代码
目前typedef只能用于声明函数类型,
若是你想定义一个Vector类(向量类),可使用如下运算符:
< | + | | | [] |
> | / | ^ | []= |
<= | ~/ | & | ~ |
>= | * | << | == |
- | % | >> |
下面为一个覆盖+和 - 运算符的类的示例:
class Vector { final int x, y; Vector(this.x, this.y); Vector operator +(Vector v) => Vector(x + v.x, y + v.y); Vector operator -(Vector v) => Vector(x - v.x, y - v.y); // Operator == and hashCode not shown. For details, see note below. // ··· } void main() { final v = Vector(2, 3); final w = Vector(2, 3); final vw = v + w; final ww = v - w; print('vw -> (${vw.x}, ${vw.y})'); print('ww -> (${ww.x}, ${ww.y})'); } //打印: vw -> (4, 6) ww -> (0, 0) 复制代码
使用var声明一个变量可是不指定其类型
var name = 'Bob'; //声明一个变量为字符串变量 复制代码
可是一旦声明赋值了为一个类型候,不能再分配给另外一个类型
咱们在继承一个类的时候,在重构一个方法时,强制将其参数由父类缩窄成其子类的话,会提示错误,例子:
//定义一个Animal类,其函数chase参数为Animal class Animal { void chase(Animal x) {} } class Mouse extends Animal { getName(){ return 'mouse'; } } class Cat extends Animal { //强制将chase函数的Animal参数缩窄成Mouse void chase(Mouse mouse) { print('cat chase ${mouse.getName()}'); } } //报错, 提示重写类型不匹配 test/test.dart:12:20: Error: The parameter 'mouse' of the method 'Cat::chase' has type #lib1::Mouse, which does not match the corresponding type in the overridden method (#lib1::Animal). Change to a supertype of #lib1::Animal (or, for a covariant parameter, a subtype). void chase(Mouse mouse) { ^ test/test.dart:2:8: Context: This is the overridden method ('chase'). void chase(Animal x) {} ^ 复制代码
使用covariant关键字后:
class Animal { void chase(Animal x) {} } class Mouse extends Animal { getName(){ return 'mouse'; } } class Cat extends Animal { void chase(covariant Mouse mouse) { print('cat chase ${mouse.getName()}'); } } void main(){ new Cat().chase(new Mouse()); } //打印 cat chase mouse 复制代码
covariant字义为协变,即我和编译器协商,这个参数缩窄变化是我故意这样作的,你别抛异常了。
Dart是一种真正的面向对象语言,所以即便是函数也是对象而且具备类型Function。 这意味着函数能够分配给变量或做为参数传递给其余函数。
//定义一个add函数 int add(int a, int b) => a+b; handle(Function function){ print('handle: ${function(1, 2)}'); //打印function的结果 } void main(){ handle(add); //调用handle并传递add函数 } //打印 handle: 3 复制代码
在Dart 1中,void仅可用做函数的返回类型(例如void main()),但在Dart 2中它已被推广,而且可在其余地方使用, 例如Future
void类型不能用于任何东西,且将某些东西分配给void类型是无效的:
void foo() {} void main() { var bar = foo(); // 无效 } 复制代码
The expression here has a type of 'void', and therefore cannot be used. -> 此表达式的类型为“void”,没法使用
在函数中,表示该函数无需返回值。
在实践中,通常使用void来表示“任何我不关心元素”,或者更常见的是,表示“省略”,例如在Future 或Stream 中。
在Java中,getter和setter应该是蛮令咱们头疼,若是一些类的属性足够多的话,提供getter和setter接口后,文件很轻松能够达到成千上百行。可是在Dart中,提供了set和get关键子来提供对象属性的读写访问权限。
class Rectangle { num left, top, width, height; Rectangle(this.left, this.top, this.width, this.height); //定义两个可计算的属性right 和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; } void main() { var rect = Rectangle(3, 4, 20, 15); print('right: ${rect.right}'); rect.right = 100; print('right: ${rect.right}'); print('bottom: ${rect.bottom}'); rect.bottom = 120; print('bottom: ${rect.bottom}'); } //打印: right: 23 right: 100 bottom: 19 bottom: 120 复制代码
在Dart中,使用get和set实现getter和setter功能,是否是简洁多了呢
使用get和set后,咱们能够从实例变量开始,在get/set的方法中用方法封装,而无需更改外部调用的代码。
while: 在循环执行以前计算条件
while (!isDone()) { doSomething(); } 复制代码
do-while: 在循环开始执行后计算条件
do { printLine(); } while (!atEndOfPage()); 复制代码
deferred用于声明一个延迟加载一个库,一般叫懒加载。容许你只有在须要使用该库的时候,再加载该库。
//文件calculate.dart class Calculate{ static String name = "Cal"; static printf(String s){ print('cal: $s'); } int add(int a, int b) => a + b; } //文件test.dart import 'calculate.dart' deferred as cal; //声明该库会延迟加载且命名为cal void main() { print('1'); greet(); print('2'); print('3'); } //异步加载库calculate.dart //加载完毕后再进行操做 Future greet() async { await cal.loadLibrary(); print('cal name: ${cal.Calculate.name}'); print('add(1, 2) = ${new cal.Calculate().add(1, 2)}'); cal.Calculate.printf('ss'); } //打印: 1 2 3 cal name: Cal add(1, 2) = 3 cal: ss 复制代码
用于在函数中返回一个值