函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。
函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!,如:
var print = (i){ console.log(i);};
[1,2,3].forEach(print);
{
"name": "hello", //调试任务名称
"program": "hello.dart", //待调试文件路径
"request": "launch", //固定的
"type": "dart" // 固定的
}
var foo = const []; // foo is currently an EIA.
final bar = const []; // bar will always be an EIA.
const baz = const []; // baz is a compile-time constant EIA.
List<int> list = const [1, 2, 3],
enableFlags({bool bold, bool hidden}) {
// ...
}
// 可选参数用=号或者:号来设置默认值,没设置就是null
void enableFlags({bool bold = false, bool hidden = false}) {
// ...
}
// 调用方式
enableFlags(bold: true, hidden: false);
// 或者不指定参数
enableFlags();
Function callback;
Function(int a) callback;
VoidCallback callback;
一个 闭包 是一个方法对象Function,不管该对象在何处被调用, 该对象都可以访问其作用域内 的变量。
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
main() {
// Create a function that adds 2.
// 不管你在那里执行 makeAdder() 所返回的函数, 都可以使用 addBy 参数。
var add2 = makeAdder(2);
assert(add2(3) == 5);
}
b ??= value; // 如果 b 是 null,则赋值给 b;
// 两个一样的编译时常量其实是 同一个对象:
var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);
assert(identical(a, b)); // They are the same instance!
where可以用来过滤集合中的某些数据
for (int i = 0; i < candidates.length; i++) {
var candidate = candidates[i];
if (candidate.yearsExperience < 5) {
continue;
}
candidate.interview();
}
// 可以这样写
candidates.where((c) => c.yearsExperience >= 5)
.forEach((c) => c.interview());
switch case中可以设置标签,用continue跳转到指定的标签处
var command = 'CLOSED';
switch (command) {
case 'CLOSED':
executeClosed();
continue nowClosed;
// Continues executing at the nowClosed label.
nowClosed:
case 'NOW_CLOSED':
// Runs for both CLOSED and NOW_CLOSED.
executeNowClosed();
break;
}
try {
breedMoreLlamas();
} on OutOfLlamasException {
// A specific exception
buyMoreLlamas();
} on Exception catch (e) {
// Anything else that is an exception
print('Unknown exception: $e');
} catch (e) {
// No specified type, handles all
print('Something really unknown: $e');
rethrow; // Allow callers to see the exception.
}
构造函数赋值简化操作
class Point {
num x;
// Syntactic sugar for setting x and y
// before the constructor body runs.
Point(this.x);
}
命名构造函数:使用命名构造函数可以为一个类实现多个构造函数,或者使用命名构造函数来更清晰的表明你的意图:
class Point {
num x;
num y;
Point(this.x, this.y);
// Named constructor
Point.fromJson(Map json) {
x = json['x'];
y = json['y'];
}
}
class Employee extends Person {
// Person does not have a default constructor;
// you must call super.fromJson(data).
Employee.fromJson(Map data) : super.fromJson(data) {
print('in Employee');
}
}
// 由于超类构造函数的参数在构造函数执行之前执行,所以 参数可以是一个表达式或者 一个方法调用(_只能是静态方法,不能是成员方法_):
class Employee extends Person {
// ...
Employee() : super.fromJson(findDefaultData());
}
冒号 (:)在构造函数体执行之前除了可以调用超类构造函数之外,还可以 初始化实例参数。
Point.fromJson(Map jsonMap)
: x = jsonMap['x'],
y = jsonMap['y'] {
print('In Point.fromJson(): ($x, $y)');
}
Point(x, y)
: x = x,
y = y,
distanceFromOrigin = sqrt(x * x + y * y);
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;
}
class Rectangle {
int width;
int height;
Point origin;
Rectangle({this.origin = const Point(0, 0), this.width = 0, this.height = 0});
@override
String toString() =>
'Origin: (${origin.x}, ${origin.y}), width: $width, height: $height';
}
main() {
print(Rectangle(origin: const Point(10, 20), width: 100, height: 200));
print(Rectangle(origin: const Point(10, 10)));
print(Rectangle(width: 200));
print(Rectangle());
}
默认构造函数就是用类名称命名的构造函数,只能有一个默认构造函数,哪怕修改参数列表也不行,之后你只能定义命名构造函数了。
有些类提供了常量构造函数。使用常量构造函数 可以创建编译时常量,要使用常量构造函数只需要用 const 替代 new 即可:
var p = const ImmutablePoint(2, 2);
两个一样的编译时常量其实是 同一个对象:
var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);
assert(identical(a, b)); // They are the same instance!
factory构造函数本质上就是一个具有返回值的函数
// 构造函数返回子类实例
const factory Key(String value) = ValueKey<String>;
// LinkedHashMap是抽象类
factory Map.from(Map other) = LinkedHashMap<K, V>.from;
这里用到了factory redirect,等效于
const factory Key(String value) => new ValueKey<String>(value);
Dart是没有interface这种东西的,但并不以为着这门语言没有接口,事实上,Dart任何一个类都是接口,你可以实现任何一个类,只需要重写那个类里面的所有具体方法。每个类都隐式的定义了一个包含所有实例成员的接口, 并且这个类实现了这个接口。如果你想 创建类 A 来支持 类 B 的 api,而不想继承 B 的实现, 则类 A 应该实现 B 的接口。就是说任何class可以被当做interface被其他用implement关键字实现,与extends关键字不同的是,实现的方法中不能调用super。
import 'dart:io';
import 'package:mylib/mylib.dart';
import 'package:utils/utils.dart' as utils;
// Import only foo.
import 'package:lib1/lib1.dart' show foo;
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
如果 Dart 类实现了 call() 函数则 可以把该类当做方法来调用。
Flutter基础:理解Dart的Mixin继承机制
mixins是一个强大的概念,允许您跨多个类层次结构重用代码。当我们想要在不共享相同类层次结构的多个类之间共享行为时,或者在超类中实现此类行为没有意义时,Mixins非常有用。
如果我们不想让我们创建的mixin被实例化或扩展,同时使用factory关键字结合_权限符
abstract class Walker {
// This class is intended to be used as a mixin, and should not be
// extended directly.
factory Walker._() => null;
void walk() {
print("I'm walking");
}
}
// 第二个参数是一个异步匿名函数,返回值是Future<dynamic>
setUp(() {
channel.setMockMethodCallHandler((MethodCall methodCall) async {
return '42';
});
});
当您需要延迟地生成一个值序列时,请考虑使用生成器函数。Dart内置支持两种生成器函数: 同步生成器:返回Iterable对象 异步生成器:返回Stream对象 要实现同步生成器函数,将函数体标记为sync,并使用yield语句传递值; 要实现异步生成器函数,将函数体标记为async,并使用yield语句传递值; 如果您的生成器是递归的,您可以使用yield*来改进它的性能:
Iterable<int> naturalsDownFrom(int n) sync* {
if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}
常用的代表泛型的字母: E代表Element,元素;T代表Type,类型;K代表Key,键;V代表Value,值. 泛型函数定义时,在函数名称后面必须有<>
isolate是有自己的内存和单线程控制的运行实体。 所有的 Dart 代码在 isolates 中运行而不是线程。 每个 isolate 都有自己的堆内存,并且确保每个 isolate 的状态都不能被其他 isolate 访问。 Dart是单线程执行模型,支持Isolates(在另一个线程上运行Dart代码的方式)、事件循环和异步编程。 除非您启动一个Isolate,否则您的Dart代码将在主UI线程中运行,并由事件循环驱动(译者语:和JavaScript一样)。
在 Dart 语言中,方法也是对象。 使用 typedef, 或者 function-type alias 来为方法类型命名, 然后可以使用命名的方法。
定义有两种形式,下面都是取了一个叫做Compare别名的方法:
typedef int Compare(int a, int b);
typedef Compare = int Function(int a, int b);
定义了一个带有两个参数的 @todo 注解
library todo;
class todo {
final String who;
final String what;
const todo(this.who, this.what);
}