当前位置: 主页 > 网络编程 > Dart >

Dart 速查表 codelab

时间:2024-01-15 22:27来源:互联网 作者:秩名 点击:
Dart 语言旨在让从其他编程语言转来的开发者们能够轻松学习,但也有它的独特之处。本篇将基于谷歌工程师编写的Dart 语言速查表为你介绍一些最重要的语言特性。 在这篇 codelab 中的

Dart 语言旨在让从其他编程语言转来的开发者们能够轻松学习,但也有它的独特之处。本篇将基于谷歌工程师编写的 Dart 语言速查表
 为你介绍一些最重要的语言特性。

在这篇 codelab 中的嵌入式编辑器已经完成了部分代码片段。你可以在这些编辑器上将代码补充完整,然后点击 Run (运行) 按钮进行测试。
如果你需要帮助,请点击 Hint (提示) 按钮。要运行代码格式化 (dart format),点击 Format (格式化) 按钮,Reset (重置) 按钮将会清除你的操作
,并把编辑器恢复到初始状态。

字符串插值

为了将表达式的值放在字符串中,请使用 ${expression}。若表达式为单个标识符,则可以省略 {}

下面是一些使用字符串插值的例子:

字符串   结果
'${3 + 2}'   '5'
'${"word".toUpperCase()}'   'WORD'
'$myObject'   myObject.toString() 的值

Code example

代码样例

下面的方法接收两个整型变量作为参数,然后让它返回一个包含以空格分隔的整数的字符串。例如,stringify(2, 3) 应该返回 '2 3'

可空的变量

Dart 要求使用健全的空安全,这意味着除非变量显式声明为可空类型,否则它们将不能为空。换句话说,类型默认是不可为空的。

举个例子,下面的代码在空安全下是有错误的,因为 int 类型的变量不能为 null

int a = null; // INVALID.

你可以通过在类型后添加 ? 来表示该类型可空:

int? a = null; // Valid.

在所有 Dart 版本中,null 在未初始化的变量里都是默认值,所以你可以这样简化你的代码:

int? a; // The initial value of a is null.

想了解更多有关 Dart 的空安全的内容,请阅读 健全的空安全。

Code example

代码样例

试着定义以下两种变量:

  • 一个可空的 String,名为 name,值为 'Jane'

  • 一个可空的 String,名为 address,值为 null

可以忽略以下代码一开始在 DartPad 中的错误。

避空运算符

Dart 提供了一系列方便的运算符用于处理可能会为空值的变量。其中一个是 ??= 赋值运算符,仅当该变量为空值时才为其赋值:

int? a; // = null
a ??= 3;
print(a); // <-- Prints 3.

a ??= 5;
print(a); // <-- Still prints 3.

另外一个避空运算符是 ??,如果该运算符左边的表达式返回的是空值,则会计算并返回右边的表达式。

print(1 ?? 3); // <-- Prints 1.
print(null ?? 12); // <-- Prints 12.

Code example

代码样例

尝试在下面的代码片段中交替使用 ??= 和 ?? 操作符,实现期望的需求。

可以忽略以下代码一开始在 DartPad 中的错误。

条件属性访问

要保护可能会为空的属性的正常访问,请在点(.)之前加一个问号(?)。

myObject?.someProperty

上述代码等效于以下内容:

(myObject != null) ? myObject.someProperty : null

你可以在一个表达式中连续使用多个 ?.

myObject?.someProperty?.someMethod()

如果 myObject 或 myObject.someProperty 为空,则前面的代码返回 null(并不再调用 someMethod)。

Code example

代码样例

尝试使用条件属性访问来完成下面的代码片段。

集合字面量 (Collection literals)

Dart 内置了对 list、map 以及 set 的支持。你可以通过字面量直接创建它们:

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

Dart 的类型推断可以自动帮你分配这些变量的类型。在这个例子中,推断类型是 List<String>Set<String>和 Map<String, int>

你也可以手动指定类型:

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

在使用子类型的内容初始化列表,但仍希望列表为 List <BaseType> 时,指定其类型很方便:

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

Code example

代码样例

尝试将以下变量设定为指定的值。替换当前的 null 值。

箭头语法

你也许已经在 Dart 代码中见到过 => 符号。这种箭头语法是一种定义函数的方法,该函数将在其右侧执行表达式并返回其值。

例如,考虑调用这个 List 类中的 any 方法:

bool hasEmpty = aListOfStrings.any((s) {
  return s.isEmpty;
});

这里是一个更简单的代码实现:

bool hasEmpty = aListOfStrings.any((s) => s.isEmpty);

Code example

代码样例

尝试使用箭头语法完成下面语句:

级联

要对同一对象执行一系列操作,请使用级联(..)。我们都看到过这样的表达式:

myObject.someMethod()

它在 myObject 上调用 someMethod 方法,而表达式的结果是 someMethod 的返回值。

下面是一个使用级连语法的相同表达式:

myObject..someMethod()

Although it still invokes someMethod() on myObject, the result of the expression isn’t the return value—it’s a reference to myObject!

虽然它仍然在 myObject 上调用了 someMethod,但表达式的结果却不是该方法返回值,而是是 myObject 对象的引用!使用级联,
你可以将需要单独操作的语句链接在一起。例如,下方的代码使用了空判断调用符 (?.) 在 button 不为 null 时获取属性:

var button = querySelector('#confirm');
button?.text = 'Confirm';
button?.classes.add('important');
button?.onClick.listen((e) => window.alert('Confirmed!'));
button?.scrollIntoView();

现在你可以在第一个级联位置,使用 空判断 级联操作符 (?..),它可以确保级联操作均在实例不为 null 时执行。使用空判断级联后,你也不再需要 button 变量了:

querySelector('#confirm')
  ?..text = 'Confirm'
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'))
  ..scrollIntoView();

Code example

代码样例

使用级联创建一个语句,分别将 BigObject 的 anInt 属性设为 1aString 属性设为 String!aList 属性设置为 [3.0] 然后调用 allDone()

Getters and setters

任何需要对属性进行更多控制而不是允许简单字段访问的时候,你都可以自定义 getter 和 setter。

例如,你可以用来确保属性值合法:

class MyClass {
  int _aProperty = 0;

  int get aProperty => _aProperty;

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

你还可以使用 getter 来定义计算属性:

class MyClass {
  final List<int> _values = [];

  void addValue(int value) {
    _values.add(value);
  }

  // A computed property.
  int get count {
    return _values.length;
  }
}

Code example

代码样例

想象你有一个购物车类,其中有一个私有的 List<double> 类型的 prices 属性。添加以下内容:

  • 一个名为 total 的 getter,用于返回总价格。

  • 只要新列表不包含任何负价格, setter 就会用新的列表替换列表(在这种情况下,setter 应该抛出 InvalidPriceException)。

可以忽略以下代码一开始在 DartPad 中的错误。

可选位置参数

Dart 有两种传参方法:位置参数和命名参数。位置参数你可能会比较熟悉:

int sumUp(int a, int b, int c) {
  return a + b + c;
}
// ···
  int total = sumUp(1, 2, 3);

在 Dart 里,你可以将这些参数包裹在方括号中,使其变成可选位置参数:

int sumUpToFive(int a, [int? b, int? c, int? d, int? e]) {
  int sum = a;
  if (b != null) sum += b;
  if (c != null) sum += c;
  if (d != null) sum += d;
  if (e != null) sum += e;
  return sum;
}
// ···
  int total = sumUpToFive(1, 2);
  int otherTotal = sumUpToFive(1, 2, 3, 4, 5);

可选位置参数永远放在方法参数列表的最后。除非你给它们提供一个默认值,否则默认为 null:

int sumUpToFive(int a, [int b = 2, int c = 3, int d = 4, int e = 5]) {
// ···
}
// ···
  int newTotal = sumUpToFive(1);
  print(newTotal); // <-- prints 15

Code example

代码样例

实现一个名为 joinWithCommas 的方法,它接收一至五个整数,然后返回由逗号分隔的包含这些数字的字符串。以下是方法调用和返回值的一些示例:

方法调用   返回值
joinWithCommas(1)   '1'
joinWithCommas(1, 2, 3)   '1,2,3'
joinWithCommas(1, 1, 1, 1, 1)   '1,1,1,1,1'

 

 

命名参数

你可以在参数列表的靠后位置使用花括号 ({}) 来定义命名参数。

除非显式使用 required 进行标记,否则命名参数默认是可选的。

void printName(String firstName, String lastName, {String? middleName}) {
  print('$firstName ${middleName ?? ''} $lastName');
}
// ···
  printName('Dash', 'Dartisan');
  printName('John', 'Smith', middleName: 'Who');
  // Named arguments can be placed anywhere in the argument list
  printName('John', middleName: 'Who', 'Smith');

正如你所料,这些参数默认为 null,但你也可以为其提供默认值。

如果一个参数的类型是非空的,那么你必须要提供一个默认值(如下方代码所示),或者将其标记为 required(如 构造部分所示)。

void printName(String firstName, String lastName, {String middleName = ''}) {
  print('$firstName $middleName $lastName');
}

一个方法不能同时使用可选位置参数和可选命名参数。

Code example

代码样例

向 MyDataObject 类添加一个 copyWith() 实例方法,它应该包含三个可空的命名参数。

  • int? newInt
  • String? newString
  • double? newDouble

copyWith 方法应该根据当前实例返回一个新的 MyDataObject 并将前面参数(如果有的话)的数据复制到对象的属性中
。例如,如果 newInt 不为空,则将其值复制到 anInt 中。

可以忽略以下代码一开始在 DartPad 中的错误。

异常

Dart 代码可以抛出和捕获异常。与 Java 相比,Dart 的所有异常都是 unchecked exception。方法不会声明它们可能抛出的
异常,你也不需要捕获任何异常。

虽然 Dart 提供了 Exception 和 Error 类型,但是你可以抛出任何非空对象:

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

使用 tryon 以及 catch 关键字来处理异常:

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

The try keyword works as it does in most other languages. Use the on keyword to filter for specific exceptions by type,
and the catch keyword to get a reference to the exception object.

如果你无法完全处理该异常,请使用 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();
}

Code example

代码样例

在下面实现 tryFunction() 方法。它应该会执行一个不可靠的方法,然后做以下操作:

  • 如果 untrustworthy() 抛出了 ExceptionWithMessage,则调用 logger.logException 并传入使用异常类型和消息(尝试使用 on 和 catch)。

  • 如果 untrustworthy() 抛出了一个 Exception,则调用 logger.logException 并传入使用异常类型(这次请尝试使用 on)。

  • 如果 untrustworthy() 抛出了其他对象,请不要捕获该异常。

  • 捕获并处理完所有内容后,调用 logger.doneLogging(尝试使用 finally)。

在构造方法中使用 this

Dart 提供了一个方便的快捷方式,用于为构造方法中的属性赋值:在声明构造方法时使用 this.propertyName

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

  MyColor(this.red, this.green, this.blue);
}

final color = MyColor(80, 80, 128);

此技巧同样也适用于命名参数。属性名为参数的名称:

class MyColor {
  ...

  MyColor({required this.red, required this.green, required this.blue});
}

final color = MyColor(red: 80, green: 80, blue: 80);

在上面的代码中,redgreen 和 blue 被标记为 required,因为这些 int 数值不能为空。如果你指定了默认值,你可以忽略 required

对于可选参数,默认值为期望值:

MyColor([this.red = 0, this.green = 0, this.blue = 0]);
// or
MyColor({this.red = 0, this.green = 0, this.blue = 0});

Code example

代码样例

使用 this 语法向 MyClass 添加一行构造方法,并接收和分配全部(三个)属性。

可以忽略以下代码一开始在 DartPad 中的错误。

Initializer lists

有时,当你在实现构造函数时,您需要在构造函数体执行之前进行一些初始化。例如,final 修饰的字段必须在构造函数体执行之前赋值。
在初始化列表中执行此操作,该列表位于构造函数的签名与其函数体之间:

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

初始化列表也是放置断言的便利位置,它仅会在开发期间运行:

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

Code example

代码样例

完成下面的 FirstTwoLetters 的构造函数。使用的初始化列表将 word 的前两个字符分配给 letterOne 和 LetterTwo 属性。
要获得额外的信用,请添加一个 断言 以捕获少于两个字符的单词。

可以忽略以下代码一开始在 DartPad 中的错误。

命名构造方法

为了允许一个类具有多个构造方法, Dart 支持命名构造方法:

class Point {
  double x, y;

  Point(this.x, this.y);

  Point.origin()
      : x = 0,
        y = 0;
}

为了使用命名构造方法,请使用全名调用它:

final myPoint = Point.origin();

Code example

代码样例

给 Color 类添加一个叫做 Color.black 的方法,它将会把三个属性的值都设为 0。

可以忽略以下代码一开始在 DartPad 中的错误。

工厂构造方法

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();

    throw ArgumentError('Unrecognized $typeName');
  }
}

Code example

代码样例

填写名为 IntegerHolder.fromList 的工厂构造方法,使其执行以下操作:

  • 若列表只有一个值,那么就用它来创建一个 IntegerSingle

  • 如果这个列表有两个值,那么按其顺序创建一个 IntegerDouble

  • 如果这个列表有三个值,那么按其顺序创建一个 IntegerTriple

  • 否则,抛出一个 Error

重定向构造方法

有时一个构造方法仅仅用来重定向到该类的另一个构造方法。重定向方法没有主体,它在冒号(:)之后调用另一个构造方法。

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

Code example

代码样例

还记得我们之前提到的 Color 类吗?创建一个叫做 black 的命名构造方法,但这次我们不要手动分配属性,而是将 0 作为参数,重定向到默认的构造方法。

可以忽略以下代码一开始在 DartPad 中的错误。

Const 构造方法

如果你的类生成的对象永远都不会更改,则可以让这些对象成为编译时常量。为此,请定义 const 构造方法并确保所有实例变量都是 final 的。

class ImmutablePoint {
  static const ImmutablePoint origin = ImmutablePoint(0, 0);

  final int x;
  final int y;

  const ImmutablePoint(this.x, this.y);
}

Code example

代码样例

修改 Recipe 类,使其实例成为常量,并创建一个执行以下操作的常量构造方法:

  • 该方法有三个参数:ingredientscalories 和 milligramsOfSodium。(按照此顺序)

  • 使用 this 语法自动将参数值分配给同名的对象属性。

  • 在 Recipe 的构造方法声明之前,用 const 关键字使其成为常量。

可以忽略以下代码一开始在 DartPad 中的错误。

(责任编辑:阿里技术)
织梦二维码生成器
顶一下
(1)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
推荐内容