Dart中的特性

原文:Dart cheatsheet codelab

1、字符串插值(String interpolation)

要将一个表达式的值放入字符串中,可以使用字符串插值${expression}

main() {
  // 字符串插值
  print(stringify(1, 3));
}

String stringify(int x, int y) {
  return '$x $y';
}

2、null感知运算符(Null-aware operators)

(1)如果一个值可能为null,可以使用??=赋值表达式,如果当前变量是null,则给变量赋一个值,注意只要变量还是null,即使再次重新使用 ??=运算符,还是第一次的值,除非中间有过不为null的值,再次使用的时候才会进行更换

int a; // 初始化值为null
a ??= 3;
print(a); // 打印值为3

a ??= 5;
print(a); // 还是3
int a; // 初始化值为null
a ??= 3;
print(a); // 打印值为3

a = 1; // a此时不为null
a = null; // 将a再次赋为null
a ??= 5; 
print(a); // 这是打印为5

(2)另一种运算符为??,如果运算符左边为null,则返回表达式右边的值

print(1 ?? 3); // 打印为1
print(null ?? 12); // 打印为12

3、条件属性访问(Conditional property access)

如果访问对象的属性或者方法可能为null,使用?.

myObject?.someProperty
// 上边等价于
(myObject != null) ? myObject.someProperty : null
// 可以用链式调用
myObject?.someProperty?.someMethod()
// 如果myObject为null或者myObject.someProperty为null,则表达式结果为null且someMethod()方法不会调用
String upperCaseIt(String str) {
  return str?.toUpperCase();
}

4、集合字面量(Collection literals)

final aListOfStrings = ['one', 'two', 'three'];
final aSetOfStrings = {'one', 'two', 'three'};
final aMapOfStringsToInts = {
  'one': 1,
  'two': 2,
  'three': 3,
};

以上类型推断为List<String>、Set<String>、Map<String, int>类型,也可以明确指出你要的类型

final aListOfInts = <int>[];
final aSetOfInts = <int>{};
final aMapOfIntToDouble = <int, double>{};

当你用子类去初始化一个列表的时候,但仍然希望列表是List<BaseType>,这时候明确类型是很方便的,如:

final aListOfBaseType = <BaseType>[SubType(), SubType()];

5、箭头语法(Arrow syntax)

箭头函数是一种定义函数的方法,该函数在其右侧执行表达式并返回它的值

var list = <String>["abc", "cbs", "dsa"];

bool hasEmpty = list.any((element) {
    return element.isEmpty;
});
// 等价于
bool hasEmpty = list.any((element) => element.isEmpty);
print(hasEmpty);

6、级联(Cascades)

 // 级联
var myObject = MyObject();
myObject.someMethod();
// 以上调用myObject的someMethod()方法,表达式的结果是返回someMethod()的值
// 查看数据类型
print(myObject.runtimeType.toString()); // MyObject
var test = myObject..someMethod();
// 以上尽管仍然是调用myObject的someMethod()方法,但结果已经不再是方法的返回值了,结果是myObject的一个引用。
// 查看数据类型
print(test.runtimeType.toString()); // MyObject

使用级联,可以将需要单独语句的操作链接在一起

var button = querySelector("#confirm");
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((event) => window.alert('Confirm!'));

// 使用级联上边的代码会变得更短,而且也不再需要button变量
querySelector("#confirm")
..text = 'Confirm'
..classes.add('important')
..onClick.listen((event) => window.alert('Confirm!'));

7、Getters and setters

当你需要对属性进行比简单字段所允许的更多的控制的时候,可以使用getters和setters

例如可以保证设置的属性是否符合某个要求

class MyClass {
  int _aProperty = 0;

  int get aProperty => _aProperty;

  set aProperty(int value) {
    if (value > 0) {
      _aProperty = value;
    }
  }
}

var myClass = MyClass();
myClass.aProperty = -10;
print(myClass.aProperty); // 0,不符合set的条件,打印出来的是初始值
myClass.aProperty = 10;
print(myClass.aProperty); // 10,符合set的条件,属性值进行了设置

注意:以上事示例中,如果先设置aProperty的值为10,后设置aProperty为-10,则打印出来的结果为10,10.这是因为最后一次赋值为-10没有满足条件,使用的是上一次赋值的结果10.

也可以使用getter方法去定义一个计算属性

class MyClass2 {
  List<int> _values = [];
  void addValue(int value) {
    return _values.add(value);
  }

  // 一个计算属性
  int get count => _values.length;
}

var myClass2 = MyClass2();
myClass2.addValue(1);
myClass2.addValue(3);
print(myClass2.count); // 2
myClass2.addValue(4);
print(myClass2.count); // 3

再举一个购物车的例子

var shoppingCart = ShoppingCart();
shoppingCart.prices = [10, 20, 50];
// shoppingCart.prices = [10, -20, 50]; 注意会抛出异常
print(shoppingCart.total); // 打印80.0

class ShoppingCart {
  List<double> _prices = [];
    
  // List的fold方法可以实现给一个初始值,然后迭代数组中的每一个元素
  double get total =>
      _prices.fold(0, (previousValue, element) => previousValue + element);

  set prices(List<double> value) {
    if (value.any((element) => element < 0)) {
      throw Exception();
    }
    _prices = value;
  }
}

8、可选位置参数(Optional positional parameters)

Dart有两种函数参数:位置参数和命名参数
位置参数的使用如下:

int sumUp(int a, int b, int c) {
  return a + b + c;
}

int total = sumUp(1, 2, 3);

在Dart中可以让位置参数用中括号包裹成为可选参数

int sumUpThree(int a, [int b, int c]) {
  int sum = a;
  if (b != null) sum += b;
  if (c != null) sum += c;
  return sum;
}

int totalThree = sumUpThree(10);
print(totalThree); // 10
totalThree = sumUpThree(10, 3);
print(totalThree); // 13
totalThree = sumUpThree(10, 3, 5);
print(totalThree); // 18

可选位置参数一般位于函数参数列表的最后,它的默认值是null,可以为可选位置参数提供默认值,如:

int sumUpThreeWithDefault(int a, [int b = 1, int c = 2]) {
  return a + b + c;
}

int totalThreeWithDefault = sumUpThreeWithDefault(1);
print(totalThreeWithDefault); // 4

9、可选命名参数(Optional named parameters)

使用大括号可以定义带名称的命名可选参数

void printName(String firstName, String lastName, {String suffix}) {
  print('$firstName $lastName ${suffix ?? ''}');
}

printName('Han', 'Qiao'); // Han Qiao
printName('Han', 'Qiao', suffix: 'A'); // Han Qiao A
printName('Han', 'Qiao', suffix: null); // Han Qiao

命名可选参数默认值为null,可以为可选命名提供默认值

void printName(String firstName, String lastName, {String suffix}) {
  print('$firstName $lastName ${suffix ?? ''}');
}

一个函数不能既有可选位置参数又有可选命名参数

10、异常(Exception)

Dart代码可以抛出和捕获异常。与Java相反,Dart的所有异常都是未检查的异常。方法不声明它们可能抛出哪些异常,也不需要捕获任何异常。

Dart提供了ExceptionError类型,但你可以抛出任何非空对象:

throw Exception('Something bad happened.');
throw 'Waaaaaaah!';

在处理异常的时候使用try, oncatch关键字

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');
}

try关键字的工作方式与大多数其他语言一样。使用on关键字按类型筛选特定的异常,使用catch关键字获得对异常对象的引用。

如果不能完全的处理异常,可以使用rethrow关键字传递异常

try {
  breedMoreLlamas();
} catch (e) {
  print('I was just trying to breed llamas!.');
  rethrow;
}

无论是否抛出异常都要执行代码,使用finally关键字

try {
  breedMoreLlamas();
} catch (e) {
  // ... handle exception ...
} finally {
  // Always clean up, even if an exception is thrown.
  cleanLlamaStalls();
}

再举一个示例:

typedef VoidFunction = void Function();

class ExceptionWithMessage {
  final String message;
  const ExceptionWithMessage(this.message);
}

abstract class Logger {
  void logException(Type t, [String msg]);
  void doneLogging();
}

void tryFunction(VoidFunction untrustworthy, Logger logger) {
  try {
    untrustworthy();
  } on ExceptionWithMessage catch (e) {
    logger.logException(e.runtimeType, e.message);
  } on Exception {
    logger.logException(Exception);
  } finally {
    logger.doneLogging();
  }
}

11、在构造函数中使用this(Using this in a constructor)

Dart为构造函数中的属性赋值提供了一个方便的快捷方式,在声明构造函数时使用this.propertyName
这个也适用于命名参数,属性名称成为命名参数。
对于可选参数,默认值在这里也同样试用

class MyColor {
  int red;
  int green;
  int blue;

  // 使用位置参数
  MyColor(this.red, this.green, this.blue);
  // 使用可选命名参数
  MyColor({this.red, this.green, this.blue});
  // 使用带默认值的可选命名参数
  MyColor({this.red = 0, this.green = 0, this.blue = 0});
  // 使用可选位置参数
  MyColor([this.red = 0, this.green = 0, this.blue = 0]);
}

// 使用位置参数调用
final color = MyColor(80, 80, 100);
// 使用可选命名参数调用
final color = MyColor(red: 80, green: 80, blue: 100);
// 使用可选位置参数调用
final color = MyColor(80, 80, 100);

12、初始化列表(Initializer list)

有时当你实现一个构造函数时,你需要在构造函数体执行之前做一些设置。例如,最终发字段在构造函数体执行之前必须有值。在构造函数的命名和它的主体之间的初始化列表中做这些工作:

Point.fromJson(Map<String, num> json)
    : x = json['x'],
      y = json['y'] {
  print('In Point.fromJson(): ($x, $y)');
}

初始化列表的位置也可以放置assert,这个在开发过程中运行,例如:

NonNegativePoint(this.x, this.y)
    : assert(x >= 0),
      assert(y >= 0) {
  print('I just made a NonNegativePoint: ($x, $y)');
}

13、命名构造函数(Named constructors)

为了允许类有多个构造函数,Dart支持命名构造函数:

class Point {
  double x, y;

  Point(this.x, this.y);

  Point.origin() {
    x = 0;
    y = 0;
  }
}

final myPoint = Point.origin();

14、工厂构造函数(Factory constructors)

Dart支持工厂构造函数,它可以返回子类型,甚至返回null。要创建工厂构造函数,使用factory关键字:

class Square extends Shape {}

class Circle extends Shape {}

class Shape {
  Shape();

  factory Shape.fromTypeName(String typeName) {
    if (typeName == 'square') return Square();
    if (typeName == 'circle') return Circle();

    print('I don\'t recognize $typeName');
    return null;
  }
}

15、重定向构造函数(Redirecting constructors)

有时,构造函数的唯一目的是重定向到同一个类中的另一个构造函数。重定向构造函数的函数体是空的,构造函数调用出现在冒号(:)之后。

class Automobile {
  String make;
  String model;
  int mpg;

  // The main constructor for this class.
  Automobile(this.make, this.model, this.mpg);

  // Delegates to the main constructor.
  Automobile.hybrid(String make, String model) : this(make, model, 60);

  // Delegates to a named constructor
  Automobile.fancyHybrid() : this.hybrid('Futurecar', 'Mark 2');
}

再比如:

class Color {
  int red;
  int green;
  int blue;
  
  Color(this.red, this.green, this.blue);

  // Create a named constructor called "black" here and redirect it
  // to call the existing constructor
  Color.black() : this(0, 0, 0);
}

16、常量构造函数(Const constructors)

如果类生成的对象永远不变,则可以将这些对象设置为编译时常量。为此,定义一个const构造函数并确保所有实例变量都是final变量。

class ImmutablePoint {
  const ImmutablePoint(this.x, this.y);

  final int x;
  final int y;

  static const ImmutablePoint origin = ImmutablePoint(0, 0);
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容