Dart 编程 - 快速指南



Dart 编程 - 概述

Dart 是一种面向对象的语言,使用 C 风格的语法,可以选择性地编译成 JavaScript。它支持各种编程辅助工具,例如接口、类、集合、泛型和可选类型。

Dart 可以广泛用于创建单页应用程序。单页应用程序仅适用于网站和 Web 应用程序。单页应用程序允许在网站的不同屏幕之间导航,而无需在浏览器中加载不同的网页。一个经典的例子是 **Gmail** - 当您在收件箱中点击一条消息时,浏览器会停留在同一网页上,但 JavaScript 代码会隐藏收件箱并在屏幕上显示邮件正文。

Google 发布了 **Chromium** 的一个特殊版本 - **Dart VM**。使用 Dartium 意味着您不必将代码编译成 JavaScript,直到您准备好测试其他浏览器。

下表比较了 Dart 和 JavaScript 的功能。

特性 Dart JavaScript
类型系统 可选的,动态的 弱类型,动态的
是,单继承 原型继承
接口 是,多接口
并发 是,使用隔离区 是,使用 HTML5 Web Workers

本教程提供了对 Dart 编程语言的基本理解。

Dart 编程 - 环境搭建

本章讨论在 Windows 平台上为 Dart 设置执行环境。

使用 DartPad 在线执行脚本

您可以使用在线编辑器 https://pad.dart.ac.cn/ 在线测试您的脚本。Dart 编辑器会执行脚本并显示 HTML 和控制台输出。在线编辑器附带了一组预设代码示例。

下面给出了 **Dartpad** 编辑器的屏幕截图 -

Dartpad

Dartpad 还允许以更严格的方式进行编码。这可以通过检查编辑器右下角的“强模式”选项来实现。强模式有助于 -

  • 更强大的静态和动态检查
  • 生成更具特色的 JavaScript 代码以实现更好的互操作性。

您可以使用 Dartpad 尝试以下示例

void main() { 
   print('hello world'); 
}

代码将显示以下输出

hello world

设置本地环境

在本节中,让我们看看如何设置本地环境。

使用文本编辑器

一些编辑器的示例包括 Windows 记事本、Notepad++、Emacs、vim 或 vi 等。编辑器可能因操作系统而异。源文件通常以“.dart”扩展名命名。

安装 Dart SDK

Dart 的当前稳定版本为 **1.21.0**。**dart sdk** 可以从以下地址下载 -

下面给出了 Dart SDK 安装的屏幕截图 -

Dart Installation

完成 SDK 安装后,将 PATH 环境变量设置为 -

<dart-sdk-path>\bin 

验证安装

要验证 Dart 是否已成功安装,请打开命令提示符并输入以下命令 -

Dart 

如果安装成功,它将显示 dart 运行时。

IDE 支持

许多 IDE 支持 Dart 脚本编写。例如 Jet brains 的 **Eclipse、IntelliJ** 和 **WebStorm**。

以下是使用 **WebStrom IDE** 配置 Dart 环境的步骤。

安装 WebStorm

WebStorm 的安装文件可以从 https://www.jetbrains.com/webstorm/download/#section=windows-version 下载。

WebStorm 安装文件适用于 Mac OS、Windows 和 Linux。

下载安装文件后,请按照以下步骤操作 -

  • 安装 Dart SDK:请参考上面列出的步骤

  • 创建一个新的 Dart 项目并配置 Dart 支持

  • 要创建一个新的 Dart 项目,

    • 从欢迎屏幕点击 **创建新项目**

    • 在下一个对话框中,点击 **Dart**

  • 如果没有为 **Dart SDK** 路径指定值,则提供 SDK 路径。例如,SDK 路径可能是 **<dart 安装目录>/dart/dartsdk**。

向项目添加 Dart 文件

要向项目添加 Dart 文件 -

  • 右键点击项目
  • 新建 → Dart 文件
  • 输入 Dart 脚本的名称

下面给出了 WebStorm 编辑器的屏幕截图 -

Dart File

dart2js 工具

**dart2js** 工具将 Dart 代码编译成 JavaScript。将 Dart 代码编译成 JS 可以在不支持 Dart VM 的浏览器上运行 Dart 脚本。

dart2js 工具作为 Dart SDK 的一部分提供,可以在 ** /dartsdk/bin 文件夹** 中找到。

要将 Dart 编译成 JavaScript,请在终端中键入以下命令

dart2js - - out = <output_file>.js  <dart_script>.dart

此命令生成一个包含 Dart 代码的 JavaScript 等效文件。有关使用此实用程序的完整教程,请参阅 Dart 官方网站。

Dart 编程 - 语法

语法定义了一组编写程序的规则。每种语言规范都定义了自己的语法。Dart 程序由以下部分组成 -

  • 变量和运算符
  • 函数
  • 表达式和编程结构
  • 决策制定和循环结构
  • 注释
  • 库和包
  • 类型定义
  • 表示为集合/泛型的的数据结构

你的第一个 Dart 代码

让我们从传统的“Hello World”示例开始 -

main() { 
   print("Hello World!"); 
}

**main()** 函数是 Dart 中的预定义方法。此方法充当应用程序的入口点。Dart 脚本需要 **main()** 方法才能执行。**print()** 是一个预定义函数,它将指定的字符串或值打印到标准输出,即终端。

以上代码的输出将是 -

Hello World!

执行 Dart 程序

您可以通过两种方式执行 Dart 程序 -

  • 通过终端
  • 通过 WebStorm IDE

通过终端

要通过终端执行 Dart 程序 -

  • 导航到当前项目的路径
  • 在终端窗口中键入以下命令
dart file_name.dart

通过 WebStorm IDE

要通过 WebStorm IDE 执行 Dart 程序 -

  • 右键点击 IDE 上的 Dart 脚本文件。(文件应包含 **main()** 函数以启用执行)

  • 点击 **“运行 <file_name>”** 选项。下面给出了相同的屏幕截图 -

Run Test1 Dart

或者,可以点击 Run Button 按钮或使用快捷键 **Ctrl+Shift+F10** 执行 Dart 脚本。

Dart 命令行选项

Dart 命令行选项用于修改 Dart 脚本执行。Dart 的常见命令行选项包括以下内容 -

序号 命令行选项 & 描述
1 -c 或 --c

启用断言和类型检查(检查模式)。

2 --version

显示 VM 版本信息。

3 --packages <path>

指定包解析配置文件的路径。

4 -p <path>

指定在何处查找导入的库。此选项不能与 --packages 一起使用。

5 -h 或 --help

显示帮助。

启用检查模式

Dart 程序以两种模式运行,即 -

  • 检查模式
  • 生产模式(默认)

建议在开发和测试期间以 **检查模式** 运行 Dart VM,因为它会添加警告和错误以帮助开发和调试过程。检查模式会强制执行各种检查,例如类型检查等。要打开检查模式,在运行脚本时,在脚本文件名之前添加 -c 或 –-checked 选项。

但是,为了确保在运行脚本时获得性能优势,建议在 **生产模式** 下运行脚本。

考虑以下 **Test.dart** 脚本文件 -

void main() { 
   int n = "hello"; 
   print(n); 
} 

通过输入以下内容运行脚本 -

dart Test.dart

尽管存在类型不匹配,但脚本仍成功执行,因为检查模式已关闭。脚本将产生以下输出 -

hello

现在尝试使用“- - checked”或“-c”选项执行脚本 -

dart -c Test.dart 

或者,

dart - - checked Test.dart

Dart VM 将抛出一个错误,指出存在类型不匹配。

Unhandled exception: 
type 'String' is not a subtype of type 'int' of 'n' where 
   String is from dart:core 
   int is from dart:core 
#0  main (file:///C:/Users/Administrator/Desktop/test.dart:3:9) 
#1  _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart :261) 
#2  _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:148)

Dart 中的标识符

标识符是赋予程序中元素(如变量、函数等)的名称。标识符的规则如下 -

标识符可以包含字符和数字。但是,标识符不能以数字开头。

  • 标识符不能包含特殊符号,下划线 (_) 或美元符号 ($) 除外。

  • 标识符不能是关键字。

  • 它们必须是唯一的。

  • 标识符区分大小写。

  • 标识符不能包含空格。

下表列出了一些有效和无效标识符的示例 -

有效标识符 无效标识符
firstName Var
first_name first name
num1 first-name
$result 1number

Dart 中的关键字

关键字在语言上下文中具有特殊含义。下表列出了 Dart 中的一些关键字。

abstract 1 continue false new this
as 1 default final null throw
assert deferred 1 finally operator 1 true
async 2 do for part 1 try
async* 2 dynamic 1 get 1 rethrow typedef 1
await 2 else if return var
break enum implements 1 set 1 void
case export 1 import 1 static 1 while
catch external 1 in super with
class extends is switch yield 2
const factory 1

库 1 同步* 2 生成* 2

空白和换行符

Dart 忽略程序中出现的空格、制表符和换行符。您可以在程序中自由使用空格、制表符和换行符,并且可以自由地以整洁一致的方式格式化和缩进程序,从而使代码易于阅读和理解。

Dart 区分大小写

Dart 区分大小写。这意味着 Dart 区分大写和小写字符。

语句以分号结尾

每行指令称为语句。每个 Dart 语句都必须以分号 (;) 结尾。一行可以包含多个语句。但是,这些语句必须用分号隔开。

Dart 中的注释

注释是提高程序可读性的一种方法。注释可用于包含有关程序的其他信息,例如代码作者、有关函数/结构的提示等。注释会被编译器忽略。

Dart 支持以下类型的注释 -

  • 单行注释 ( // ) - "//" 和行尾之间的任何文本都被视为注释

  • 多行注释 (/* */) - 这些注释可以跨越多行。

示例

// this is single line comment  
  
/* This is a   
   Multi-line comment  
*/ 

Dart 中的面向对象编程

Dart 是一种面向对象的语言。面向对象是一种软件开发范式,遵循现实世界的建模。面向对象将程序视为对象的集合,这些对象通过称为方法的机制相互通信。

  • 对象 - 对象是任何实体的实时表示。根据 Grady Brooch 的说法,每个对象都必须具有三个特征 -

    • 状态 - 由对象的属性描述。

    • 行为 - 描述对象将如何行动。

    • 标识 - 一个唯一的值,将对象与一组类似的对象区分开来。

  • - 从 OOP 的角度来看,类是创建对象的蓝图。类封装了对象的数据。

  • 方法 - 方法促进对象之间的通信。

示例:Dart 和面向对象

class TestClass {   
   void disp() {     
      print("Hello World"); 
   } 
}  
void main() {   
   TestClass c = new TestClass();   
   c.disp();  
}

以上示例定义了一个类 TestClass。该类有一个方法 disp()。该方法在终端上打印字符串“Hello World”。new 关键字创建类的对象。该对象调用方法 disp()

代码应产生以下输出 -

Hello World

Dart 编程 - 数据类型

编程语言最基本的特点之一是它支持的数据类型集。这些是在编程语言中可以表示和操作的值的类型。

Dart 语言支持以下类型 -

  • 数字
  • 字符串
  • 布尔值
  • 列表
  • 映射

数字

Dart 中的数字用于表示数字文字。Dart 数字有两种类型 -

  • 整数 - 整数值表示非分数值,即没有小数点的数值。例如,值“10”是整数。整数文字使用int关键字表示。

  • 双精度浮点数 - Dart 也支持分数数值,即带小数点的值。Dart 中的 Double 数据类型表示一个 64 位(双精度)浮点数。例如,值“10.10”。double关键字用于表示浮点文字。

字符串

字符串表示字符序列。例如,如果您要存储一些数据,例如姓名、地址等,则应使用字符串数据类型。Dart 字符串是 UTF-16 代码单元的序列。符文用于表示 UTF-32 代码单元的序列。

String关键字用于表示字符串文字。字符串值嵌入在单引号或双引号中。

布尔值

布尔数据类型表示布尔值 true 和 false。Dart 使用bool关键字表示布尔值。

列表和映射

列表和映射数据类型用于表示对象的集合。列表是有序的对象组。Dart 中的 List 数据类型与其他编程语言中数组的概念同义。映射数据类型表示一组键值对形式的值。dart:core库分别通过预定义的 List 和 Map 类启用这些集合的创建和操作。

动态类型

Dart 是一种可选类型语言。如果未显式指定变量的类型,则变量的类型为dynamicdynamic关键字也可以用作类型注释。

Dart 编程 - 变量

变量是“内存中命名的空间”,用于存储值。换句话说,它充当程序中值的容器。变量名称为标识符。以下是标识符的命名规则 -

  • 标识符不能是关键字。

  • 标识符可以包含字母和数字。

  • 标识符不能包含空格和特殊字符,除了下划线 (_) 和美元符号 ($)。

  • 变量名不能以数字开头。

类型语法

必须在使用变量之前声明它。Dart 使用 var 关键字来实现这一点。声明变量的语法如下所示 -

var name = 'Smith';

Dart 中的所有变量都存储对值的引用,而不是包含值本身。名为 name 的变量包含对值为“Smith”的 String 对象的引用。

Type Syntax

Dart 通过在变量名前添加数据类型来支持类型检查。类型检查确保变量仅保存特定于数据类型的数据。相同的语法如下所示 -

String name = 'Smith'; 
int num = 10;

考虑以下示例 -

void main() { 
   String name = 1; 
}

以上代码段将产生警告,因为分配给变量的值与变量的数据类型不匹配。

输出

Warning: A value of type 'String' cannot be assigned to a variable of type 'int' 

所有未初始化的变量的初始值均为 null。这是因为 Dart 将所有值视为对象。以下示例说明了这一点 -

void main() { 
   int num; 
   print(num); 
}

输出

Null 

dynamic 关键字

未声明静态类型的变量隐式声明为 dynamic。变量也可以使用 dynamic 关键字代替 var 关键字进行声明。

以下示例说明了这一点。

void main() { 
   dynamic x = "tom"; 
   print(x);  
}

输出

tom

final 和 const

finalconst关键字用于声明常量。Dart 阻止修改使用 final 或 const 关键字声明的变量的值。这些关键字可以与变量的数据类型一起使用,也可以代替var关键字使用。

const关键字用于表示编译时常量。使用const关键字声明的变量隐式为 final。

语法:final 关键字

final variable_name

final data_type  variable_name

语法:const 关键字

const variable_name

const data_type variable_name

示例 – final 关键字

void main() { 
   final val1 = 12; 
   print(val1); 
}

输出

12

示例 – const 关键字

void main() { 
   const pi = 3.14; 
   const area = pi*12*12; 
   print("The output is ${area}"); 
}

以上示例使用const关键字声明了两个常量piareaarea变量的值是编译时常量。

输出

The output is 452.15999999999997

注意 - 只有const变量才能用于计算编译时常量。编译时常量是在编译时确定其值的常量

示例

如果尝试修改使用final或 const 关键字声明的变量,Dart 会抛出异常。以下示例说明了这一点 -

void main() { 
   final v1 = 12; 
   const v2 = 13; 
   v2 = 12; 
}

上面给出的代码将抛出以下错误作为输出 -

Unhandled exception: 
cannot assign to final variable 'v2='.  
NoSuchMethodError: cannot assign to final variable 'v2=' 
#0  NoSuchMethodError._throwNew (dart:core-patch/errors_patch.dart:178) 
#1      main (file: Test.dart:5:3) 
#2    _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:261) 
#3    _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:148)

Dart 编程 - 运算符

表达式是一种特殊的语句,它计算出一个值。每个表达式都由 -

  • 操作数 - 表示数据

  • 运算符 - 定义如何处理操作数以生成值。

考虑以下表达式 – "2 + 3"。在此表达式中,2 和 3 是操作数,符号 "+"(加号)是运算符

在本章中,我们将讨论 Dart 中可用的运算符。

  • 算术运算符
  • 相等和关系运算符
  • 类型测试运算符
  • 按位运算符
  • 赋值运算符
  • 逻辑运算符

算术运算符

下表显示了 Dart 支持的算术运算符。

显示示例

序号 运算符和含义
1 +

2

3 -expr

一元减号,也称为否定(反转表达式的符号)

4 *

5 /

6 ~/

除,返回整数结果

7 %

获取整数除法的余数(模)

8 ++

递增

9 --

递减

相等和关系运算符

关系运算符测试或定义两个实体之间关系的类型。关系运算符返回布尔值,即 true/false。

假设 A 的值为 10,B 的值为 20。

显示示例

运算符 描述 示例
> 大于 (A > B) 为 False
< 小于 (A < B) 为 True
>= 大于或等于 (A >= B) 为 False
<= 小于或等于 (A <= B) 为 True
== 相等 (A==B) 为 False
!= 不相等 (A!=B) 为 True

类型测试运算符

这些运算符对于在运行时检查类型非常方便。

显示示例

运算符 含义
is 如果对象具有指定的类型,则为 True
is! 如果对象具有指定的类型,则为 False

按位运算符

下表列出了 Dart 中可用的按位运算符及其作用 -

显示示例

运算符 描述 示例
按位与 a & b 在每个位位置返回 1,对于这两个操作数的相应位均为 1。
按位或 a | b 在每个位位置返回 1,对于这两个操作数的相应位为 1 或两者均为 1。
按位异或 a ^ b 在每个位位置返回 1,对于这两个操作数的相应位为 1,但不是两者均为 1。
按位非 ~ a 反转其操作数的位。
左移 a ≪ b 将 a 的二进制表示形式向左移动 b (< 32) 位,从右侧移入零。
带符号右移 a ≫ b 将 a 的二进制表示形式向右移动 b (< 32) 位,丢弃移出的位。

赋值运算符

下表列出了 Dart 中可用的赋值运算符。

显示示例

序号 运算符和描述
1 =(简单赋值)

将右侧操作数的值赋给左侧操作数

示例:C = A + B 会将 A + B 的值赋给 C

2 ??=

仅当变量为空时才赋值

3 +=(加法和赋值)

它将右侧操作数加到左侧操作数,并将结果赋给左侧操作数。

示例:C += A 等价于 C = C + A

4 ─=(减法和赋值)

它从左侧操作数中减去右侧操作数,并将结果赋给左侧操作数。

示例:C -= A 等价于 C = C – A

5 *=(乘法和赋值)

它将右侧操作数乘以左侧操作数,并将结果赋给左侧操作数。

示例:C *= A 等价于 C = C * A

6 /=(除法和赋值)

它将左侧操作数除以右侧操作数,并将结果赋给左侧操作数。

注意 - 位运算符也适用相同的逻辑,因此它们将变为 ≪=、≫=、≫=、≫=、|= 和 ^=。

逻辑运算符

逻辑运算符用于组合两个或多个条件。逻辑运算符返回布尔值。假设变量 A 的值为 10,B 的值为 20。

显示示例

运算符 描述 示例
&&

- 只有当所有指定的表达式都返回 true 时,运算符才返回 true

(A > 10 && B > 10) 为假。
||

- 如果指定的表达式中至少有一个返回 true,则运算符返回 true

(A > 10 || B > 10) 为真。
!

- 运算符返回表达式的结果的反值。例如:!(7>5) 返回 false

!(A > 10) 为真。

条件表达式

Dart 有两个运算符,允许您评估可能需要 ifelse 语句的表达式 -

condition ? expr1 : expr2

如果 condition 为真,则表达式计算 expr1(并返回其值);否则,它计算并返回 expr2 的值。

expr1 ?? expr2

如果 expr1 不为 null,则返回其值;否则,计算并返回 expr2 的值

示例

以下示例显示了如何在 Dart 中使用条件表达式 -

void main() { 
   var a = 10; 
   var res = a > 12 ? "value greater than 10":"value lesser than or equal to 10"; 
   print(res); 
} 

它将产生以下输出 -

value lesser than or equal to 10

示例

让我们看另一个例子 -

void main() { 
   var a = null; 
   var b = 12; 
   var res = a ?? b; 
   print(res); 
}

它将产生以下输出 -

12

Dart 编程 - 循环

有时,某些指令需要重复执行。循环是执行此操作的理想方法。循环表示必须重复的一组指令。在循环的上下文中,重复称为迭代

下图说明了循环的分类 -

Classification Of Loops

让我们从确定循环开始讨论。迭代次数确定/固定的循环称为确定循环

序号 循环 & 描述
1 for 循环

for 循环是确定循环的一种实现。for 循环执行代码块指定次数。它可以用于迭代一组固定的值,例如数组

2 for...in 循环

for...in 循环用于循环遍历对象的属性。

接下来,让我们讨论不确定循环。当循环的迭代次数不确定或未知时,使用不确定循环。不确定循环可以使用 -

序号 循环 & 描述
1 while 循环

while 循环每次指定的条件计算结果为 true 时都执行指令。换句话说,循环在执行代码块之前评估条件。

2 do…while 循环

do…while 循环类似于 while 循环,只是 do...while 循环在第一次执行循环时不评估条件。

现在让我们继续讨论 Dart 的循环控制语句

序号 控制语句 & 描述
1 break 语句

break 语句用于将控制权从构造中取出。在循环中使用break 会导致程序退出循环。以下是break 语句的示例。

2 continue 语句

continue 语句跳过当前迭代中的后续语句,并将控制权返回到循环的开头。

使用标签控制流程

标签只是一个后跟冒号 (:) 的标识符,应用于语句或代码块。标签可以与breakcontinue 一起使用以更精确地控制流程。

‘continue’‘break’ 语句与其标签名称之间不允许换行。此外,标签名称和关联循环之间也不应有任何其他语句。

示例:带 Break 的标签

void main() { 
   outerloop: // This is the label name 
   
   for (var i = 0; i < 5; i++) { 
      print("Innerloop: ${i}"); 
      innerloop: 
      
      for (var j = 0; j < 5; j++) { 
         if (j > 3 ) break ; 
         
         // Quit the innermost loop 
         if (i == 2) break innerloop; 
         
         // Do the same thing 
         if (i == 4) break outerloop; 
         
         // Quit the outer loop 
         print("Innerloop: ${j}"); 
      } 
   } 
}

在成功执行上述代码后,将显示以下输出

Innerloop: 0
Innerloop: 0
Innerloop: 1
Innerloop: 2
Innerloop: 3
Innerloop: 1
Innerloop: 0
Innerloop: 1
Innerloop: 2
Innerloop: 3
Innerloop: 2
Innerloop: 3
Innerloop: 0
Innerloop: 1
Innerloop: 2
Innerloop: 3
Innerloop: 4

示例:带 continue 的标签

void main() { 
   outerloop: // This is the label name 
   
   for (var i = 0; i < 3; i++) { 
      print("Outerloop:${i}"); 
      
      for (var j = 0; j < 5; j++) { 
         if (j == 3){ 
            continue outerloop; 
         } 
         print("Innerloop:${j}"); 
      } 
   } 
}

在成功执行上述代码后,将显示以下输出。

Outerloop: 0 
Innerloop: 0 
Innerloop: 1 
Innerloop: 2 

Outerloop: 1 
Innerloop: 0 
Innerloop: 1 
Innerloop: 2 

Outerloop: 2 
Innerloop: 0 
Innerloop: 1 
Innerloop: 2 

Dart 编程 - 条件语句

条件/决策构造在执行指令之前评估条件。

Decision Making

Dart 中的条件构造在以下表格中分类。

序号 语句 & 描述
1 if 语句

if 语句由一个布尔表达式后跟一个或多个语句组成。

2 If...Else 语句

if 后面可以跟一个可选的else 块。如果if 块测试的布尔表达式计算结果为 false,则将执行else 块。

3 else…if 梯

else…if 梯用于测试多个条件。以下是相同的语法。

4 switch…case 语句

switch 语句评估表达式,将表达式的值与 case 子句匹配,并执行与该 case 关联的语句。

Dart 编程 - 数字

Dart 数字可以分类为 -

  • int - 任意大小的整数。int 数据类型用于表示整数。

  • double - 64 位(双精度)浮点数,如 IEEE 754 标准所指定。double 数据类型用于表示小数

num 类型由intdouble 类型继承。dart core 库允许对数值执行许多操作。

声明数字的语法如下所示 -

int var_name;      // declares an integer variable 
double var_name;   // declares a double variable 

示例

void main() {
   // declare an integer
   int num1 = 10;             
     
   // declare a double value
   double num2 = 10.50;  

   // print the values
   print(num1);
   print(num2);
}

它将产生以下输出 -

10 
10.5 

注意 - 如果将小数赋值给整数变量,则Dart VM 将抛出异常。

解析

parse() 静态函数允许将包含数字字面量的字符串解析为数字。以下说明演示了相同 -

void main() { 
   print(num.parse('12')); 
   print(num.parse('10.91')); 
}

以上代码将产生以下输出 -

12 
10.91

如果传递给 parse() 函数的值不是数字,则 parse 函数会抛出 FormatException。以下代码显示了如何将字母数字值传递给parse() 函数。

示例

void main() { 
   print(num.parse('12A')); 
   print(num.parse('AAAA')); 
}

以上代码将产生以下输出 -

Unhandled exception: 
FormatException: 12A 
#0 num.parse (dart:core/num.dart:446) 
#1 main (file:///D:/Demos/numbers.dart:4:13) 
#2 _startIsolate.<anonymous closure> (dart:isolatepatch/isolate_patch.dart:261) 
#3 _RawReceivePortImpl._handleMessage (dart:isolatepatch/isolate_patch.dart:148)

数字属性

下表列出了 Dart 数字支持的属性。

序号 属性 & 描述
1 hashcode

返回数值的哈希码。

2 isFinite

如果数字是有限的,则为真;否则为假。

3 isInfinite

如果数字是正无穷大或负无穷大,则为真;否则为假。

4 isNan

如果数字是双精度非数字值,则为真;否则为假。

5 isNegative

如果数字为负,则为真;否则为假。

6 sign

根据数字的符号和数值返回负一、零或正一。

7 isEven

如果数字是偶数,则返回 true。

8 isOdd

如果数字是奇数,则返回 true。

数字方法

下面列出了数字支持的一些常用方法 -

序号 方法 & 描述
1 abs

返回数字的绝对值。

2 ceil

返回不小于数字的最小整数。

3 compareTo

将此与其他数字进行比较。

4 Floor

返回不大于当前数字的最大整数。

5 remainder

返回两个数字相除后的截断余数。

6 Round

返回最接近当前数字的整数。

7 toDouble

返回数字的双精度等效值。

8 toInt

返回数字的整数等效值。

9 toString

返回数字的字符串等效表示形式。

10 truncate

丢弃任何小数位后返回一个整数。

Dart 编程 - 字符串

String 数据类型表示字符序列。Dart 字符串是 UTF 16 代码单元的序列。

Dart 中的字符串值可以使用单引号或双引号或三引号表示。单行字符串使用单引号或双引号表示。三引号用于表示多行字符串。

在 Dart 中表示字符串值的语法如下所示 -

语法

String  variable_name = 'value'  

OR  

String  variable_name = ''value''  

OR  

String  variable_name = '''line1 
line2'''  

OR  

String  variable_name= ''''''line1 
line2''''''

以下示例说明了在 Dart 中使用 String 数据类型。

void main() { 
   String str1 = 'this is a single line string'; 
   String str2 = "this is a single line string"; 
   String str3 = '''this is a multiline line string'''; 
   String str4 = """this is a multiline line string"""; 
   
   print(str1);
   print(str2); 
   print(str3); 
   print(str4); 
}

它将产生以下输出 -

this is a single line string 
this is a single line string 
this is a multiline line string 
this is a multiline line string 

字符串是不可变的。但是,字符串可以进行各种操作,并且结果字符串可以存储为新值。

字符串插值

通过将值附加到静态字符串来创建新字符串的过程称为连接插值。换句话说,它是将一个字符串添加到另一个字符串的过程。

加号运算符 (+) 是连接/插值字符串的常用机制。

示例 1

void main() { 
   String str1 = "hello"; 
   String str2 = "world"; 
   String res = str1+str2; 
   
   print("The concatenated string : ${res}"); 
}

它将产生以下输出 -

The concatenated string : Helloworld

示例 2

您可以使用 "${}" 用于在字符串中插值 Dart 表达式的值。以下示例说明了相同。

void main() { 
   int n=1+1; 
   
   String str1 = "The sum of 1 and 1 is ${n}"; 
   print(str1); 
   
   String str2 = "The sum of 2 and 2 is ${2+2}"; 
   print(str2); 
}

它将产生以下输出 -

The sum of 1 and 1 is 2 
The sum of 2 and 2 is 4

字符串属性

下表中列出的属性都是只读的。

序号 属性 & 描述
1 codeUnits

返回此字符串的 UTF-16 代码单元的不可修改列表。

2 isEmpty

如果此字符串为空,则返回 true。

3 Length

返回字符串的长度,包括空格、制表符和换行符。

操作字符串的方法

dart: core 库中的 String 类还提供用于操作字符串的方法。其中一些方法如下所示 -

序号 方法 & 描述
1 toLowerCase()

将此字符串中的所有字符转换为小写。

2 toUpperCase()

将此字符串中的所有字符转换为大写。

3 trim()

返回没有前导和尾随空格的字符串。

4 compareTo()

将此对象与另一个对象进行比较。

5 replaceAll()

用给定值替换与指定模式匹配的所有子字符串。

6 split()

在指定分隔符的匹配项处分割字符串,并返回子字符串列表。

7 substring()

返回此字符串的子字符串,该子字符串从 startIndex(包含)扩展到 endIndex(不包含)。

8 toString()

返回此对象的字符串表示形式。

9 codeUnitAt()

返回给定索引处的 16 位 UTF-16 代码单元。

Dart 编程 - 布尔值

Dart 为布尔数据类型提供了内置支持。DART 中的布尔数据类型仅支持两个值 - true 和 false。关键字 bool 用于在 DART 中表示布尔文字。

在 DART 中声明布尔变量的语法如下所示:

bool var_name = true;  
OR  
bool var_name = false 

示例

void main() { 
   bool test; 
   test = 12 > 5; 
   print(test); 
}

它将产生以下输出 -

true 

示例

与 JavaScript 不同,布尔数据类型只识别文字 true 为真。任何其他值都被视为假。请考虑以下示例:

var str = 'abc'; 
if(str) { 
   print('String is not empty'); 
} else { 
   print('Empty String'); 
} 

如果在 JavaScript 中运行上述代码片段,则会打印消息“字符串不为空”,因为如果字符串不为空,则 if 结构将返回 true。

但是,在 Dart 中,str 被转换为false,因为 str != true。因此,代码片段将打印消息“空字符串”(在未经检查模式下运行时)。

示例

如果在已检查模式下运行上述代码片段,则会抛出异常。下面说明了这一点:

void main() { 
   var str = 'abc'; 
   if(str) { 
      print('String is not empty'); 
   } else { 
      print('Empty String'); 
   } 
}

它将在已检查模式下产生以下输出

Unhandled exception: 
type 'String' is not a subtype of type 'bool' of 'boolean expression' where 
   String is from dart:core 
   bool is from dart:core  
#0 main (file:///D:/Demos/Boolean.dart:5:6) 
#1 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:261) 
#2 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:148)

它将在未经检查模式下产生以下输出

Empty String

注意 - WebStorm IDE 默认以已检查模式运行。

Dart 编程 - 列表

编程中一个非常常用的集合是数组。Dart 以List对象的形势表示数组。List只是一个对象的排序组。dart:core库提供了 List 类,使您可以创建和操作列表。

Dart 中列表的逻辑表示如下所示:

Logical Representation of a List
  • test_list - 是引用集合的标识符。

  • 列表包含值 12、13 和 14。保存这些值的内存块称为元素

  • List 中的每个元素都由一个唯一的数字标识,称为索引。索引从开始,扩展到n-1,其中n是 List 中元素的总数。索引也称为下标

列表可以分类为:

  • 固定长度列表
  • 可增长列表

现在让我们详细讨论这两种类型的列表

固定长度列表

固定长度列表的长度在运行时不能更改。创建固定长度列表的语法如下所示:

步骤 1 - 声明列表

声明固定长度列表的语法如下所示:

var list_name = new List(initial_size)

上述语法创建一个指定大小的列表。列表在运行时不能增长或缩小。任何尝试调整列表大小的操作都将导致异常。

步骤 2 - 初始化列表

初始化列表的语法如下所示:

lst_name[index] = value;

示例

void main() { 
   var lst = new List(3); 
   lst[0] = 12; 
   lst[1] = 13; 
   lst[2] = 11; 
   print(lst); 
}

它将产生以下输出 -

[12, 13, 11]

可增长列表

可增长列表的长度可以在运行时更改。声明和初始化可增长列表的语法如下所示:

步骤 1 - 声明列表

var list_name = [val1,val2,val3]   
--- creates a list containing the specified values  
OR  
var list_name = new List() 
--- creates a list of size zero 

步骤 2 - 初始化列表

索引/下标用于引用应填充值的元素。初始化列表的语法如下所示:

list_name[index] = value;

示例

以下示例显示了如何创建包含 3 个元素的列表。

void main() { 
   var num_list = [1,2,3]; 
   print(num_list); 
}

它将产生以下输出 -

[1, 2, 3]

示例

以下示例使用空 List() 构造函数创建了一个零长度列表。List类中的add()函数用于动态地向列表中添加元素。

void main() { 
   var lst = new List(); 
   lst.add(12); 
   lst.add(13); 
   print(lst); 
} 

它将产生以下输出 -

[12, 13] 

列表属性

下表列出了dart:core 库List类的一些常用属性。

序号 方法 & 描述
1 first

返回列表中的第一个元素。

2 isEmpty

如果集合没有元素,则返回 true。

3 isNotEmpty

如果集合至少包含一个元素,则返回 true。

4 length

返回列表的大小。

5 last

返回列表中的最后一个元素。

6 reversed

返回一个可迭代对象,其中包含按反序排列的列表值。

7 Single

检查列表是否只有一个元素并返回它。

Dart 编程 - 列表(基本操作)

在本章中,我们将讨论如何对列表执行一些基本操作,例如:

序号 基本操作和说明
1 将元素插入列表

可变列表可以在运行时动态增长。List.add()函数将指定值附加到 List 的末尾,并返回一个修改后的 List 对象。

2 更新列表

Dart 中的列表可以通过以下方式更新:

3 删除列表项

dart:core 库中 List 类支持的以下函数可用于删除 List 中的项目。

Dart 编程 - 映射

Map 对象是一个简单的键/值对。Map 中的键和值可以是任何类型。Map 是一个动态集合。换句话说,Map可以在运行时增长和缩小。

Map 可以通过两种方式声明:

  • 使用 Map 字面量
  • 使用 Map 构造函数

使用 Map 字面量声明 Map

要使用 Map 字面量声明 Map,您需要将键值对括在一对花括号"{ }"中。

以下是其语法

var identifier = { key1:value1, key2:value2 [,…..,key_n:value_n] }

使用 Map 构造函数声明 Map

要使用 Map 构造函数声明 Map,我们需要两个步骤。首先,声明 Map,其次,初始化 Map。

声明 Map语法如下:

var identifier = new Map()

现在,使用以下语法初始化 Map

map_name[key] = value

示例:Map 字面量

void main() { 
   var details = {'Usrname':'tom','Password':'pass@123'}; 
   print(details); 
}

它将产生以下输出 -

{Usrname: tom, Password: pass@123}

示例:在运行时向 Map 字面量添加值

void main() { 
   var details = {'Usrname':'tom','Password':'pass@123'}; 
   details['Uid'] = 'U1oo1'; 
   print(details); 
} 

它将产生以下输出 -

{Usrname: tom, Password: pass@123, Uid: U1oo1}

示例:Map 构造函数

void main() { 
   var details = new Map(); 
   details['Usrname'] = 'admin'; 
   details['Password'] = 'admin@123'; 
   print(details); 
} 

它将产生以下输出 -

{Usrname: admin, Password: admin@123}

注意 - Map 值可以是任何对象,包括 NULL。

Map – 属性

dart:core 包中的Map类定义了以下属性:

序号 属性 & 描述
1 Keys

返回表示键的可迭代对象

2 Values

返回表示值的可迭代对象

3 Length

返回 Map 的大小

4 isEmpty

如果 Map 是一个空 Map,则返回 true

5 isNotEmpty

如果 Map 是一个空 Map,则返回 true

Map - 函数

以下是 Dart 中用于操作 Map 的常用函数。

序号 函数名称和说明
1 addAll()

将 other 的所有键值对添加到此 Map 中。

2 clear()

从 Map 中删除所有对。

3 remove()

如果存在,则从 Map 中删除键及其关联的值。

4 forEach()

将 f 应用于 Map 的每个键值对。

Dart 编程 - 符号

Dart 中的符号是不透明的,是用于从库中反射元数据的动态字符串名称。简而言之,符号是存储人类可读字符串和计算机使用的优化字符串之间关系的一种方式。

反射是一种在运行时获取类型元数据(例如类中的方法数量、它具有的构造函数数量或函数中的参数数量)的机制。您甚至可以调用在运行时加载的类型的某个方法。

在 Dart 中,dart:mirrors包中提供了特定于反射的类。此库适用于 Web 应用程序和命令行应用程序。

语法

Symbol obj = new Symbol('name');  
// expects a name of class or function or library to reflect 

name必须是有效的公共 Dart 成员名称、公共构造函数名称或库名称。

示例

请考虑以下示例。代码在foo_lib库中声明了一个类Foo。该类定义了方法m1、m2m3

Foo.dart

library foo_lib;   
// libarary name can be a symbol   

class Foo {         
   // class name can be a symbol  
   m1() {        
      // method name can be a symbol 
      print("Inside m1"); 
   } 
   m2() { 
      print("Inside m2"); 
   } 
   m3() { 
      print("Inside m3"); 
   } 
}

以下代码加载Foo.dart库并搜索 Foo 类,借助 Symbol 类型。由于我们正在从上述库中反射元数据,因此代码导入dart:mirrors库。

FooSymbol.dart

import 'dart:core'; 
import 'dart:mirrors'; 
import 'Foo.dart';  

main() { 
   Symbol lib = new Symbol("foo_lib");   
   //library name stored as Symbol 
   
   Symbol clsToSearch = new Symbol("Foo");  
   // class name stored as Symbol  
   
   if(checkIf_classAvailableInlibrary(lib, clsToSearch))  
   // searches Foo class in foo_lib library 
      print("class found.."); 
}  
   
bool checkIf_classAvailableInlibrary(Symbol libraryName, Symbol className) { 
   MirrorSystem mirrorSystem = currentMirrorSystem(); 
   LibraryMirror libMirror = mirrorSystem.findLibrary(libraryName); 
      
   if (libMirror != null) { 
      print("Found Library"); 
      print("checkng...class details.."); 
      print("No of classes found is : ${libMirror.declarations.length}"); 
      libMirror.declarations.forEach((s, d) => print(s));  
         
      if (libMirror.declarations.containsKey(className)) return true; 
      return false; 
   } 
}

请注意,行 libMirror.declarations.forEach((s, d) => print(s)); 将在运行时遍历库中的每个声明,并打印声明作为Symbol类型。

此代码应产生以下输出

Found Library 
checkng...class details.. 
No of classes found is : 1 
Symbol("Foo") // class name displayed as symbol  
class found. 

示例:显示类的实例方法的数量

现在让我们考虑显示类中的实例方法的数量。预定义类ClassMirror帮助我们实现了这一点。

import 'dart:core'; 
import 'dart:mirrors'; 
import 'Foo.dart';  

main() { 
   Symbol lib = new Symbol("foo_lib"); 
   Symbol clsToSearch = new Symbol("Foo");  
   reflect_InstanceMethods(lib, clsToSearch); 
}  
void reflect_InstanceMethods(Symbol libraryName, Symbol className) { 
   MirrorSystem mirrorSystem = currentMirrorSystem(); 
   LibraryMirror libMirror = mirrorSystem.findLibrary(libraryName); 
   
   if (libMirror != null) { 
      print("Found Library"); 
      print("checkng...class details.."); 
      print("No of classes found is : ${libMirror.declarations.length}"); 
      libMirror.declarations.forEach((s, d) => print(s));  
      
      if (libMirror.declarations.containsKey(className)) print("found class");
      ClassMirror classMirror = libMirror.declarations[className]; 
      
      print("No of instance methods found is ${classMirror.instanceMembers.length}");
      classMirror.instanceMembers.forEach((s, v) => print(s)); 
   } 
}    

此代码应产生以下输出

Found Library 
checkng...class details.. 
No of classes found is : 1 
Symbol("Foo") 
found class 
No of instance methods found is 8 
Symbol("==") 
Symbol("hashCode") 
Symbol("toString") 
Symbol("noSuchMethod") 
Symbol("runtimeType") 
Symbol("m1") 
Symbol("m2") 
Symbol("m3")

将 Symbol 转换为字符串

您可以使用MirrorSystem类将存储在符号中的类型(如类或库)的名称转换回字符串。以下代码显示了如何将符号转换为字符串。

import 'dart:mirrors'; 
void main(){ 
   Symbol lib = new Symbol("foo_lib"); 
   String name_of_lib = MirrorSystem.getName(lib); 
   
   print(lib); 
   print(name_of_lib); 
}

它应产生以下输出

Symbol("foo_lib")   

foo_lib     

Dart 编程 - 字符串码点

字符串是一系列字符。Dart 将字符串表示为一系列 Unicode UTF-16 代码单元。Unicode 是一种格式,为每个字母、数字和符号定义一个唯一的数值。

由于 Dart 字符串是一系列 UTF-16 代码单元,因此字符串中的 32 位 Unicode 值使用特殊语法表示。rune是表示 Unicode 代码点的整数。

dart:core库中的 String 类提供了访问rune的机制。可以通过三种方式访问字符串代码单元/rune:

  • 使用 String.codeUnitAt() 函数
  • 使用 String.codeUnits 属性
  • 使用 String.runes 属性

String.codeUnitAt() 函数

可以通过其索引访问字符串中的代码单元。返回给定索引处的 16 位 UTF-16 代码单元。

语法

String.codeUnitAt(int index);

示例

import 'dart:core'; 
void main(){ 
   f1(); 
} 
f1() { 
   String x = 'Runes'; 
   print(x.codeUnitAt(0)); 
}

它将产生以下输出 -

82

String.codeUnits 属性

此属性返回指定字符串的 UTF-16 代码单元的不可修改列表。

语法

String. codeUnits;

示例

import 'dart:core';  
void main(){ 
   f1(); 
}  
f1() { 
   String x = 'Runes'; 
   print(x.codeUnits); 
} 

它将产生以下输出 -

[82, 117, 110, 101, 115]

String.runes 属性

此属性返回此string.Runes的可迭代 Unicode 代码点。扩展了可迭代。

语法

String.runes

示例

void main(){ 
   "A string".runes.forEach((int rune) { 
      var character=new String.fromCharCode(rune); 
      print(character); 
   });  
} 

它将产生以下输出 -

A 
s 
t 
r 
i 
n 
g

Unicode 代码点通常表示为\uXXXX,其中 XXXX 是一个 4 位十六进制值。要指定多于或少于 4 个十六进制数字,请将值放在花括号中。可以使用 dart:core 库中 Runes 类的构造函数来实现相同的功能。

示例

main() { 
   Runes input = new Runes(' \u{1f605} '); 
   print(new String.fromCharCodes(input)); 
}  

它将产生以下输出 -

Runes

Dart 编程 - 枚举

枚举用于定义命名常量值。枚举类型使用enum关键字声明。

语法

enum enum_name {  
   enumeration list 
}

其中,

  • enum_name指定枚举类型名称
  • enumeration list是标识符的逗号分隔列表

枚举列表中的每个符号都代表一个整数,比它前面的符号大 1。默认情况下,第一个枚举符号的值为 0。

例如

enum Status { 
   none, 
   running, 
   stopped, 
   paused 
}

示例

enum Status { 
   none, 
   running, 
   stopped, 
   paused 
}  
void main() { 
   print(Status.values); 
   Status.values.forEach((v) => print('value: $v, index: ${v.index}'));
   print('running: ${Status.running}, ${Status.running.index}'); 
   print('running index: ${Status.values[1]}'); 
}

它将产生以下输出 -

[Status.none, Status.running, Status.stopped, Status.paused] 
value: Status.none, index: 0 
value: Status.running, index: 1 
value: Status.stopped, index: 2 
value: Status.paused, index: 3 
running: Status.running, 1 
running index: Status.running 

Dart 编程 - 函数

函数是可读、可维护和可重用代码的构建块。函数是一组用于执行特定任务的语句。函数将程序组织成逻辑代码块。函数定义后,可以调用它们来访问代码。这使得代码可重用。此外,函数使程序代码易于阅读和维护。

函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实际主体。

序号 函数和说明
1 定义函数

函数定义指定特定任务将如何完成。

2 调用函数

必须调用函数才能执行它。

3 返回函数

函数也可以将值与控制一起返回给调用方。

4 参数化函数

参数是将值传递给函数的一种机制。

可选参数

当不需要强制传递参数以执行函数时,可以使用可选参数。可以通过在其名称后附加问号来将参数标记为可选。可选参数应设置为函数中的最后一个参数。

Dart 中有三种类型的可选参数:

序号 参数和说明
1 可选位置参数

要指定可选位置参数,请使用方括号 []。

2 可选命名参数

与位置参数不同,在传递值时必须指定参数的名称。花括号 {} 可用于指定可选命名参数。

3 具有默认值的可选参数

函数参数也可以分配默认值。但是,这些参数也可以显式地传递值。

递归 Dart 函数

递归是一种通过让函数重复调用自身直到获得结果来迭代操作的技术。当您需要在循环中从函数内部重复调用相同的函数并使用不同的参数时,最适合应用递归。

示例

void main() { 
   print(factorial(6));
}  
factorial(number) { 
   if (number <= 0) {         
      // termination case 
      return 1; 
   } else { 
      return (number * factorial(number - 1));    
      // function invokes itself 
   } 
}   

它应产生以下输出

720

Lambda 函数

Lambda 函数是一种表示函数的简洁机制。这些函数也称为箭头函数。

语法

[return_type]function_name(parameters)=>expression;

示例

void main() { 
   printMsg(); 
   print(test()); 
}  
printMsg()=>
print("hello"); 

int test()=>123;                       
// returning function

它应产生以下输出

hello 123 

Dart 编程 - 接口

接口定义了任何实体必须遵守的语法。接口定义了一组对象上可用的方法。Dart 没有声明接口的语法。在 Dart 中,类声明本身就是接口。

应该使用 implements 关键字才能使用接口。实现类必须提供所有实现接口函数的具体实现,这是强制性的。换句话说,一个类必须重新定义它希望实现的接口中的每个函数。

语法:实现接口

class identifier implements interface_name

示例

在下面的程序中,我们声明了一个类PrinterConsolePrinter 类实现了Printer 类的隐式接口声明。main 函数使用new 关键字创建了ConsolePrinter 类的一个对象。此对象用于调用ConsolePrinter 类中定义的函数print_data

void main() { 
   ConsolePrinter cp= new ConsolePrinter(); 
   cp.print_data(); 
}  
class Printer { 
   void print_data() { 
      print("__________Printing Data__________"); 
   } 
}  
class ConsolePrinter implements Printer { 
   void print_data() {  
      print("__________Printing to Console__________"); 
   } 
} 

它应产生以下输出

__________Printing to Console__________

实现多个接口

一个类可以实现多个接口。接口之间用逗号分隔。相同的语法如下所示:

class identifier implements interface-1,interface_2,interface_4…….

以下示例演示了如何在 Dart 中实现多个接口:

void main() { 
   Calculator c = new Calculator(); 
   print("The gross total : ${c.ret_tot()}"); 
   print("Discount :${c.ret_dis()}"); 
}  
class Calculate_Total { 
   int ret_tot() {} 
}  
class Calculate_Discount { 
   int ret_dis() {} 
}
class Calculator  implements Calculate_Total,Calculate_Discount { 
   int ret_tot() { 
      return 1000; 
   } 
   int ret_dis() { 
      return 50; 
   } 
}

它应产生以下输出

The gross total: 1000 
Discount:50 

Dart 编程 - 类

Dart 是一种面向对象的语言。它支持面向对象编程特性,如类、接口等。从 OOP 的角度来看,是创建对象的蓝图。封装了对象的数据。Dart 为此概念提供了内置支持,称为

声明类

使用class 关键字在 Dart 中声明。类定义以关键字 class 开头,后跟类名;以及用一对花括号括起来的类体。相同的语法如下所示:

语法

class class_name {  
   <fields> 
   <getters/setters> 
   <constructors> 
   <functions> 
}

class 关键字后跟类名。命名类时必须考虑标识符的规则。

类定义可以包含以下内容:

  • 字段 - 字段是在类中声明的任何变量。字段表示与对象相关的数据。

  • Setter 和 Getter - 允许程序初始化和检索类的字段的值。每个类都关联一个默认的 getter/setter。但是,可以通过显式定义 setter/getter 来覆盖默认的 getter/setter。

  • 构造函数 - 负责为类的对象分配内存。

  • 函数 - 函数表示对象可以执行的操作。它们有时也称为方法。

这些组件组合在一起称为类的数据成员

示例:声明一个类

class Car {  
   // field 
   String engine = "E1001";  
   
   // function 
   void disp() { 
      print(engine); 
   } 
}

此示例声明了一个类Car。该类有一个名为engine 的字段。disp() 是一个简单的函数,用于打印字段engine 的值。

创建类的实例

要创建类的实例,请使用new 关键字后跟类名。相同的语法如下所示:

语法

var object_name = new class_name([ arguments ])
  • new 关键字负责实例化。

  • 表达式的右侧调用构造函数。如果构造函数是参数化的,则应向其传递值。

示例:实例化一个类

var obj = new Car("Engine 1")

访问属性和函数

可以通过对象访问类的属性和函数。使用“.” 点表示法(称为句点)来访问类的成员数据。

//accessing an attribute 
obj.field_name  

//accessing a function 
obj.function_name()

示例

请查看以下示例,了解如何在 Dart 中访问属性和函数:

void main() { 
   Car c= new Car(); 
   c.disp(); 
}  
class Car {  
   // field 
   String engine = "E1001";  
   
   // function 
   void disp() { 
      print(engine); 
   } 
}

以上代码的输出如下:

E1001

Dart 构造函数

构造函数是类的特殊函数,负责初始化类的变量。Dart 使用与类名相同的名称定义构造函数。构造函数是一个函数,因此可以是参数化的。但是,与函数不同,构造函数不能有返回类型。如果您不声明构造函数,则会为您提供一个默认的无参数构造函数

语法

Class_name(parameter_list) { 
   //constructor body 
}

示例

以下示例演示了如何在 Dart 中使用构造函数:

void main() { 
   Car c = new Car('E1001'); 
} 
class Car { 
   Car(String engine) { 
      print(engine); 
   } 
}

它应产生以下输出

E1001 

命名构造函数

Dart 提供命名构造函数来使类能够定义多个构造函数。命名构造函数的语法如下所示:

语法:定义构造函数

Class_name.constructor_name(param_list)

示例

以下示例演示了如何在 Dart 中使用命名构造函数:

void main() {           
   Car c1 = new Car.namedConst('E1001');                                       
   Car c2 = new Car(); 
}           
class Car {                   
   Car() {                           
      print("Non-parameterized constructor invoked");
   }                                   
   Car.namedConst(String engine) { 
      print("The engine is : ${engine}");    
   }                               
}

它应产生以下输出

The engine is : E1001 
Non-parameterized constructor invoked

this 关键字

this 关键字引用类的当前实例。在这里,参数名称和类字段的名称相同。因此,为了避免歧义,类字段以this 关键字为前缀。以下示例说明了这一点:

示例

以下示例说明了如何在 Dart 中使用this 关键字:

void main() { 
   Car c1 = new Car('E1001'); 
}  
class Car { 
   String engine; 
   Car(String engine) { 
      this.engine = engine; 
      print("The engine is : ${engine}"); 
   } 
} 

它应产生以下输出

The engine is : E1001

Dart 类 ─ Getter 和 Setter

GetterSetter,也称为访问器修改器,分别允许程序初始化和检索类字段的值。Getter 或访问器使用get 关键字定义。Setter 或修改器使用set 关键字定义。

每个类都关联一个默认的 getter/setter。但是,可以通过显式定义 setter/getter 来覆盖默认的 getter/setter。getter 没有参数并返回值,而 setter 有一个参数并且不返回值。

语法:定义 getter

Return_type  get identifier 
{ 
} 

语法:定义 setter

set identifier 
{ 
}

示例

以下示例演示了如何在 Dart 类中使用gettersetter

class Student { 
   String name; 
   int age; 
    
   String get stud_name { 
      return name; 
   } 
    
   void set stud_name(String name) { 
      this.name = name; 
   } 
   
   void set stud_age(int age) { 
      if(age<= 0) { 
        print("Age should be greater than 5"); 
      }  else { 
         this.age = age; 
      } 
   } 
   
   int get stud_age { 
      return age;     
   } 
}  
void main() { 
   Student s1 = new Student(); 
   s1.stud_name = 'MARK'; 
   s1.stud_age = 0; 
   print(s1.stud_name); 
   print(s1.stud_age); 
} 

此程序代码应产生以下输出

Age should be greater than 5 
MARK 
Null 

类继承

Dart 支持继承的概念,即程序能够从现有类创建新类。用于扩展以创建新类的类称为父类/超类。新创建的类称为子类/子类。

一个类使用“extends”关键字从另一个类继承。子类继承父类中的所有属性和方法,除了构造函数

语法

class child_class_name extends parent_class_name 

注意 - Dart 不支持多重继承。

示例:类继承

在以下示例中,我们声明了一个类ShapeCircle 类扩展了该类。由于类之间存在继承关系,因此子类,即Car 类可以隐式访问其父类的数据成员。

void main() { 
   var obj = new Circle(); 
   obj.cal_area(); 
}  
class Shape { 
   void cal_area() { 
      print("calling calc area defined in the Shape class"); 
   } 
}  
class Circle extends Shape {}

它应产生以下输出

calling calc area defined in the Shape class

继承类型

继承可以分为以下三种类型:

  • 单一 - 每个类最多可以从一个父类继承。

  • 多重 - 一个类可以从多个类继承。Dart 不支持多重继承。

  • 多级 - 一个类可以从另一个子类继承。

示例

以下示例演示了多级继承的工作原理:

void main() { 
   var obj = new Leaf(); 
   obj.str = "hello"; 
   print(obj.str); 
}  
class Root { 
   String str; 
}  
class Child extends Root {}  
class Leaf extends Child {}  
//indirectly inherits from Root by virtue of inheritance

Leaf 类通过多级继承从 Root 和 Child 类派生属性。其输出如下所示:

hello

Dart – 类继承和方法重写

方法重写是一种机制,子类可以通过它重新定义其父类中的方法。以下示例说明了这一点:

示例

void main() { 
   Child c = new Child(); 
   c.m1(12); 
} 
class Parent { 
   void m1(int a){ print("value of a ${a}");} 
}  
class Child extends Parent { 
   @override 
   void m1(int b) { 
      print("value of b ${b}"); 
   } 
}

它应产生以下输出

value of b 12

重写方法时,函数参数的数量和类型必须匹配。如果参数数量或其数据类型不匹配,Dart 编译器将抛出错误。以下插图说明了这一点:

import 'dart:io'; 
void main() { 
   Child c = new Child(); 
   c.m1(12); 
} 
class Parent { 
   void m1(int a){ print("value of a ${a}");} 
} 
class Child extends Parent { 
   @override 
   void m1(String b) { 
      print("value of b ${b}");
   } 
}

它应产生以下输出

value of b 12

static 关键字

static 关键字可以应用于类的成员数据,即字段方法。静态变量保留其值,直到程序执行完成。静态成员由类名引用。

示例

class StaticMem { 
   static int num;  
   static disp() { 
      print("The value of num is ${StaticMem.num}")  ; 
   } 
}  
void main() { 
   StaticMem.num = 12;  
   // initialize the static variable } 
   StaticMem.disp();   
   // invoke the static method 
}

它应产生以下输出

The value of num is 12

super 关键字

super 关键字用于引用类的直接父类。该关键字可以用于引用变量、属性方法的超类版本。以下示例说明了这一点:

示例

void main() { 
   Child c = new Child(); 
   c.m1(12); 
} 
class Parent { 
   String msg = "message variable from the parent class"; 
   void m1(int a){ print("value of a ${a}");} 
} 
class Child extends Parent { 
   @override 
   void m1(int b) { 
      print("value of b ${b}"); 
      super.m1(13); 
      print("${super.msg}")   ; 
   } 
}

它应产生以下输出

value of b 12 
value of a 13 
message variable from the parent class

Dart 编程 - 对象

面向对象编程将对象定义为“任何具有定义边界的实体”。对象具有以下特征:

  • 状态 - 描述对象。类的字段表示对象的状态。

  • 行为 - 描述对象可以做什么。

  • 标识 - 一个唯一的值,用于区分一组类似的其他对象中的对象。两个或多个对象可以共享状态和行为,但不能共享标识。

句点运算符(.) 与对象一起使用以访问类的数据成员。

示例

Dart 以对象的形式表示数据。Dart 中的每个类都扩展了 Object 类。下面是一个创建和使用对象的简单示例。

class Student { 
   void test_method() { 
      print("This is a  test method"); 
   } 
   
   void test_method1() { 
      print("This is a  test method1"); 
   } 
}  
void main()    { 
   Student s1 = new Student(); 
   s1.test_method(); 
   s1.test_method1(); 
}

它应产生以下输出

This is a test method 
This is a test method1

级联运算符 (..)

上面的示例在类中调用方法。但是,每次调用函数时,都需要引用该对象。级联运算符可以用作简写,在存在一系列调用时。

级联 ( .. ) 运算符可用于通过对象发出一系列调用。上面的示例可以改写如下。

class Student { 
   void test_method() { 
      print("This is a  test method"); 
   } 
   
   void test_method1() { 
      print("This is a  test method1"); 
   } 
}  
void main() { 
   new Student() 
   ..test_method() 
   ..test_method1(); 
}

它应产生以下输出

This is a test method 
This is a test method1

toString() 方法

此函数返回对象的字符串表示形式。请查看以下示例,了解如何使用toString 方法。

void main() { 
   int n = 12; 
   print(n.toString()); 
} 

它应产生以下输出

12

Dart 编程 - 集合

与其他编程语言不同,Dart 不支持数组。Dart 集合可用于复制诸如数组之类的的数据结构。dart:core 库和其他类在 Dart 脚本中启用了集合支持。

Dart 集合基本上可以分为:

序号 Dart 集合和描述
1 List

List 只是一个对象的排序组。dart:core 库提供了 List 类,该类支持列表的创建和操作。

  • 固定长度列表 - 列表的长度在运行时不能更改。

  • 可增长列表 - 列表的长度可以在运行时更改。

2 Set

Set 表示对象的集合,其中每个对象只能出现一次。dart:core 库提供了 Set 类来实现这一点。

3 映射

Map 对象是一个简单的键/值对。Map 中的键和值可以是任何类型。Map 是一个动态集合。换句话说,Map 可以在运行时增长和缩小。dart:core 库中的 Map 类为此提供了支持。

4 Queue

Queue 是一个可以在两端进行操作的集合。当您想要构建一个先进先出集合时,队列很有用。简单来说,队列从一端插入数据,从另一端删除数据。值按插入顺序删除/读取。

迭代集合

dart:core 库中的 Iterator 类支持轻松遍历集合。每个集合都有一个iterator 属性。此属性返回一个指向集合中对象的迭代器。

示例

以下示例说明了如何使用迭代器对象遍历集合。

import 'dart:collection'; 
void main() { 
   Queue numQ = new Queue(); 
   numQ.addAll([100,200,300]);  
   Iterator i= numQ.iterator; 
   
   while(i.moveNext()) { 
      print(i.current); 
   } 
}

moveNext() 函数返回一个布尔值,指示是否存在后续条目。迭代器对象的current 属性返回迭代器当前指向的对象的值。

此程序应产生以下输出

100 
200 
300

Dart 编程 - 泛型

Dart 是一种可选类型语言。默认情况下,Dart 中的集合是异构的。换句话说,单个 Dart 集合可以容纳各种类型的值。但是,可以使 Dart 集合保存同构值。泛型概念可以用来实现这一点。

泛型的使用对集合中可以包含的值的数据类型施加了限制。此类集合被称为类型安全的集合。类型安全是一种编程特性,它确保内存块只能包含特定数据类型的数据。

所有 Dart 集合都通过泛型支持类型安全实现。一对包含数据类型的尖括号用于声明类型安全的集合。声明类型安全集合的语法如下所示。

语法

Collection_name <data_type> identifier= new Collection_name<data_type> 

下面给出了 List、Map、Set 和 Queue 的类型安全实现。此功能也受上述所有集合类型的所有实现支持。

示例:泛型 List

void main() { 
   List <String> logTypes = new List <String>(); 
   logTypes.add("WARNING"); 
   logTypes.add("ERROR"); 
   logTypes.add("INFO");  
   
   // iterating across list 
   for (String type in logTypes) { 
      print(type); 
   } 
}

它应产生以下输出

WARNING 
ERROR 
INFO

尝试插入除指定类型以外的值将导致编译错误。以下示例说明了这一点。

示例

void main() { 
   List <String> logTypes = new List <String>(); 
   logTypes.add(1); 
   logTypes.add("ERROR"); 
   logTypes.add("INFO"); 
  
   //iterating across list 
   for (String type in logTypes) { 
      print(type); 
   } 
} 

它应产生以下输出

1                                                                                     
ERROR                                                                             
INFO

示例:泛型 Set

void main() { 
   Set <int>numberSet = new  Set<int>(); 
   numberSet.add(100); 
   numberSet.add(20); 
   numberSet.add(5); 
   numberSet.add(60);
   numberSet.add(70); 
   
   // numberSet.add("Tom"); 
   compilation error; 
   print("Default implementation  :${numberSet.runtimeType}");  
   
   for(var no in numberSet) { 
      print(no); 
   } 
} 

它应产生以下输出

Default implementation :_CompactLinkedHashSet<int> 
100 
20 
5 
60 
70

示例:泛型 Queue

import 'dart:collection'; 
void main() { 
   Queue<int> queue = new Queue<int>(); 
   print("Default implementation ${queue.runtimeType}");  
   queue.addLast(10); 
   queue.addLast(20); 
   queue.addLast(30); 
   queue.addLast(40); 
   queue.removeFirst();  
   
   for(int no in queue){ 
      print(no); 
   } 
}

它应产生以下输出

Default implementation ListQueue<int> 
20 
30 
40

泛型 Map

类型安全的映射声明指定了以下数据类型:

语法

Map <Key_type, value_type>

示例

void main() { 
   Map <String,String>m={'name':'Tom','Id':'E1001'}; 
   print('Map :${m}'); 
} 

它应产生以下输出

Map :{name: Tom, Id: E1001}

Dart 编程 - 包

包是一种封装一组编程单元的机制。应用程序有时可能需要集成一些第三方库或插件。每种语言都有一个管理外部包的机制,例如 Java 的 Maven 或 Gradle、.NET 的 Nuget、Node.js 的 npm 等。Dart 的包管理器是pub

Pub 帮助在存储库中安装包。托管的包存储库可以在 https://pub.dartlang.org/ 找到。

包元数据在文件pubspec.yaml中定义。YAML 是Yet Another Markup Language的首字母缩写词。pub工具可用于下载应用程序所需的所有各种库。

每个 Dart 应用程序都有一个pubspec.yaml文件,其中包含应用程序对其他库的依赖项以及应用程序的元数据,例如应用程序名称、作者、版本和描述。

pubspec.yaml文件的内容应如下所示:

name: 'vector_victor' 
version: 0.0.1 
description: An absolute bare-bones web app. 
... 
dependencies: browser: '>=0.10.0 <0.11.0' 

重要的pub 命令如下:

序号 命令 & 描述
1

‘pub get’

帮助获取应用程序依赖的所有包。

2

‘pub upgrade’

将所有依赖项升级到较新版本。

3

‘pub build’

这用于构建 Web 应用程序,它将创建一个 build 文件夹,其中包含所有相关的脚本。

4

‘pub help’

这将为您提供所有不同 pub 命令的帮助。

如果您使用的是 WebStorm 等 IDE,则可以右键单击 pubspec.yaml 以直接获取所有命令:

Pubspec.yaml

安装包

考虑一个应用程序需要解析 xml 的示例。Dart XML 是一个轻量级库,它是开源且稳定的,用于解析、遍历、查询和构建 XML 文档。

实现上述任务的步骤如下:

步骤 1 - 将以下内容添加到 pubspec.yaml 文件中。

name: TestApp 
version: 0.0.1 
description: A simple console application. 
#dependencies: 
#  foo_bar: '>=1.0.0 <2.0.0' 
dependencies: https://mail.google.com/mail/u/0/images/cleardot.gif
xml: 

右键单击pubspec.yaml并获取依赖项。这将在内部触发pub get 命令,如下所示。

Pub Get Command

下载的包及其依赖包可以在 packages 文件夹下进行验证。

Packages

由于安装已完成,现在我们需要在项目中引用dart xml。语法如下:

import 'package:xml/xml.dart' as xml;

读取 XML 字符串

要读取 XML 字符串并验证输入,Dart XML 使用parse()方法。语法如下:

xml.parse(String input):

示例:解析 XML 字符串输入

以下示例显示了如何解析 XML 字符串输入:

import 'package:xml/xml.dart' as xml; 
void main(){ 
   print("xml"); 
   var bookshelfXml = '''<?xml version = "1.0"?> 
   <bookshelf> 
      <book> 
         <title lang = "english">Growing a Language</title> 
         <price>29.99</price> 
      </book> 
      
      <book> 
         <title lang = "english">Learning XML</title> 
         <price>39.95</price> 
      </book> 
      <price>132.00</price> 
   </bookshelf>'''; 
   
   var document = xml.parse(bookshelfXml); 
   print(document.toString()); 
}

它应产生以下输出

xml 
<?xml version = "1.0"?><bookshelf> 
   <book> 
      <title lang = "english">Growing a Language</title> 
      <price>29.99</price> 
   </book> 

   <book> 
      <title lang = "english">Learning XML</title> 
      <price>39.95</price> 
   </book> 
   <price>132.00</price> 
</bookshelf> 

Dart 编程 - 异常

异常(或异常事件)是在程序执行期间出现的问题。当发生异常时,程序的正常流程被打断,程序/应用程序异常终止。

内置的 Dart 异常包括:

序号 异常 & 描述
1

DeferredLoadException

当延迟加载的库加载失败时抛出。

2

FormatException

当字符串或其他一些数据没有预期的格式并且无法解析或处理时抛出的异常。

3

IntegerDivisionByZeroException

当一个数字除以零时抛出。

4

IOException

所有输入输出相关异常的基类。

5

IsolateSpawnException

当无法创建隔离区时抛出。

6

Timeout

当等待异步结果时发生计划的超时时抛出。

Dart 中的每个异常都是预定义类Exception的子类型。必须处理异常以防止应用程序突然终止。

try / on / catch 块

try块嵌入可能导致异常的代码。当需要指定异常类型时使用 on 块。当处理程序需要异常对象时使用catch块。

try块后面必须紧跟一个on / catch块或一个finally块(或两者之一)。当 try 块中发生异常时,控制权将转移到catch

处理异常的语法如下所示:

try { 
   // code that might throw an exception 
}  
on Exception1 { 
   // code for handling exception 
}  
catch Exception2 { 
   // code for handling exception 
} 

以下是一些需要记住的要点:

  • 代码片段可以有多个 on / catch 块来处理多个异常。

  • on 块和 catch 块是互斥的,即 try 块可以同时与 on 块和 catch 块关联。

以下代码说明了 Dart 中的异常处理:

示例:使用 ON 块

以下程序除以变量xy分别表示的两个数字。代码抛出异常,因为它尝试除以零。on 块包含处理此异常的代码。

main() { 
   int x = 12; 
   int y = 0; 
   int res;  
   
   try {
      res = x ~/ y; 
   } 
   on IntegerDivisionByZeroException { 
      print('Cannot divide by zero'); 
   } 
} 

它应产生以下输出

Cannot divide by zero

示例:使用 catch 块

在以下示例中,我们使用了与上面相同的代码。唯一的区别是catch 块(而不是 ON 块)此处包含处理异常的代码。catch的参数包含在运行时抛出的异常对象。

main() { 
   int x = 12; 
   int y = 0; 
   int res;  
   
   try {  
      res = x ~/ y; 
   }  
   catch(e) { 
      print(e); 
   } 
} 

它应产生以下输出

IntegerDivisionByZeroException

示例:on…catch

以下示例显示了如何使用on...catch块。

main() { 
   int x = 12; 
   int y = 0; 
   int res;  
   
   try { 
      res = x ~/ y; 
   }  
   on IntegerDivisionByZeroException catch(e) { 
      print(e); 
   } 
} 

它应产生以下输出

IntegerDivisionByZeroException

Finally 块

finally块包含无论异常是否发生都应执行的代码。可选的finally块在try/on/catch之后无条件执行。

使用finally块的语法如下:

try { 
   // code that might throw an exception 
}  
on Exception1 { 
   // exception handling code 
}  
catch Exception2 { 
   //  exception handling 
}  
finally { 
   // code that should always execute; irrespective of the exception 
}

以下示例说明了finally块的使用。

main() { 
   int x = 12; 
   int y = 0; 
   int res;  
   
   try { 
      res = x ~/ y; 
   } 
   on IntegerDivisionByZeroException { 
      print('Cannot divide by zero'); 
   } 
   finally { 
      print('Finally block executed'); 
   } 
}

它应产生以下输出

Cannot divide by zero 
Finally block executed

抛出异常

throw关键字用于显式引发异常。应处理引发的异常以防止程序突然退出。

显式引发异常的语法为:

throw new Exception_name()

示例

以下示例显示了如何使用throw关键字抛出异常:

main() { 
   try { 
      test_age(-2); 
   } 
   catch(e) { 
      print('Age cannot be negative'); 
   } 
}  
void test_age(int age) { 
   if(age<0) { 
      throw new FormatException(); 
   } 
}

它应产生以下输出

Age cannot be negative

自定义异常

如上所述,Dart 中的每个异常类型都是内置类Exception的子类型。Dart 通过扩展现有异常来创建自定义异常。定义自定义异常的语法如下所示:

语法:定义异常

class Custom_exception_Name implements Exception { 
   // can contain constructors, variables and methods 
} 

自定义异常应显式引发,并且应在代码中进行处理。

示例

以下示例显示了如何定义和处理自定义异常。

class AmtException implements Exception { 
   String errMsg() => 'Amount should be greater than zero'; 
}  
void main() { 
   try { 
      withdraw_amt(-1); 
   } 
   catch(e) { 
      print(e.errMsg()); 
   }  
finally { 
      print('Ending requested operation.....'); 
   } 
}  
void withdraw_amt(int amt) { 
   if (amt <= 0) { 
      throw new AmtException(); 
   } 
}  

在上面的代码中,我们正在定义一个自定义异常AmtException。如果传递的金额不在预期范围内,代码将引发异常。main函数将函数调用包含在try...catch块中。

代码应产生以下输出 -

Amount should be greater than zero 
Ending requested operation.... 

Dart 编程 - 调试

开发人员在编码时会不时地犯错误。程序中的错误称为 bug。查找和修复 bug 的过程称为调试,是开发过程的正常部分。本节介绍可以帮助您完成调试任务的工具和技术。

WebStorm 编辑器支持断点和逐步调试。程序将在附加断点的位置中断。此功能类似于您可能从 Java 或 C# 应用程序开发中获得的功能。您可以观察变量、浏览堆栈、单步执行和进入方法和函数调用,所有这些都来自 WebStorm 编辑器。

添加断点

考虑以下代码片段。(TestString.dart)

void main() { 
   int a = 10, b = 20, c = 5; 
   c = c * c * c; 
   
   print("$a + $b = ${a+b}"); 
   print("$a%$b = ${a%b}");  // Add a break point here 
   print("$a*$b = ${a*b}"); 
   print("$a/$b = ${a/b}"); 
   print(c); 
}

添加断点,请单击左侧边距。在下图中,第 7 行有一个断点。

Add a Breakpoint

在调试模式下运行程序。在项目资源管理器中,右键单击 Dart 程序,在本例中为 TestString.dart。

Debug TestString

程序在调试模式下运行后,您将获得如下所示的调试器窗口。变量选项卡显示当前上下文中变量的值。您可以为特定变量添加观察器,并使用观察器窗口监听这些值的更改。

Add Watchers

Step Into(F7)调试菜单上的箭头图标有助于逐语句执行代码。如果主方法调用子例程,则这也将进入子例程代码。

Step Over(F8):它类似于Step Into。使用上的差异发生在当前语句包含对子例程的调用时。如果主方法调用子例程,则 Step Over 不会深入子例程。它将跳过子例程。

Step Out(Shift+F8):执行当前执行点所在的函数的其余行。显示的下一条语句是子例程调用后的语句。

在调试模式下运行后,程序给出以下输出

10 + 20 = 30 
10 % 20 = 10 
10 * 20 = 200 
10 / 20 = 0.5 
125

Dart 编程 - 类型定义

typedef或函数类型别名有助于定义指向内存中可执行代码的指针。简单来说,typedef可以作为引用函数的指针使用。

以下是 Dart 程序中实现typedef的步骤。

步骤 1:定义 typedef

typedef可用于指定我们希望特定函数匹配的函数签名。函数签名由函数的参数(包括其类型)定义。返回类型不是函数签名的一部分。其语法如下。

typedef function_name(parameters)

步骤 2:将函数分配给 typedef 变量

typedef的变量可以指向任何具有与typedef相同签名的函数。您可以使用以下签名将函数分配给typedef变量。

type_def  var_name = function_name

步骤 3:调用函数

typedef变量可用于调用函数。以下是如何调用函数:

var_name(parameters) 

示例

现在让我们举一个例子来了解 Dart 中的typedef

首先,让我们定义一个typedef。在这里,我们正在定义一个函数签名。该函数将接收两个类型为integer的输入参数。返回类型不是函数签名的一部分。

typedef ManyOperation(int firstNo , int secondNo); //function signature

接下来,让我们定义函数。定义一些与ManyOperation typedef具有相同函数签名的函数。

Add(int firstNo,int second){ 
   print("Add result is ${firstNo+second}"); 
}  
Subtract(int firstNo,int second){ 
   print("Subtract result is ${firstNo-second}"); 
}  
Divide(int firstNo,int second){ 
   print("Add result is ${firstNo/second}"); 
}

最后,我们将通过typedef调用函数。声明一个 ManyOperations 类型的变量。将函数名称分配给声明的变量。

ManyOperation oper ;  

//can point to any method of same signature 
oper = Add; 
oper(10,20); 
oper = Subtract; 
oper(30,20); 
oper = Divide; 
oper(50,5); 

oper变量可以指向任何接收两个整数参数的方法。Add函数的引用被分配给该变量。Typedef可以在运行时切换函数引用

现在让我们将所有部分放在一起,看看完整的程序。

typedef ManyOperation(int firstNo , int secondNo); 
//function signature  

Add(int firstNo,int second){ 
   print("Add result is ${firstNo+second}"); 
} 
Subtract(int firstNo,int second){ 
   print("Subtract result is ${firstNo-second}"); 
}
Divide(int firstNo,int second){ 
   print("Divide result is ${firstNo/second}"); 
}  
Calculator(int a, int b, ManyOperation oper){ 
   print("Inside calculator"); 
   oper(a,b); 
}  
void main(){ 
   ManyOperation oper = Add; 
   oper(10,20); 
   oper = Subtract; 
   oper(30,20); 
   oper = Divide; 
   oper(50,5); 
} 

程序应产生以下输出

Add result is 30 
Subtract result is 10 
Divide result is 10.0 

注意 - 如果typedef变量试图指向具有不同函数签名的函数,则上述代码将导致错误。

示例

Typedef也可以作为参数传递给函数。考虑以下示例:

typedef ManyOperation(int firstNo , int secondNo);   //function signature 
Add(int firstNo,int second){ 
   print("Add result is ${firstNo+second}"); 
}  
Subtract(int firstNo,int second){
   print("Subtract result is ${firstNo-second}"); 
}  
Divide(int firstNo,int second){ 
   print("Divide result is ${firstNo/second}"); 
}  
Calculator(int a,int b ,ManyOperation oper){ 
   print("Inside calculator"); 
   oper(a,b); 
}  
main(){ 
   Calculator(5,5,Add); 
   Calculator(5,5,Subtract); 
   Calculator(5,5,Divide); 
} 

它将产生以下输出 -

Inside calculator 
Add result is 10 
Inside calculator 
Subtract result is 0 
Inside calculator 
Divide result is 1.0

Dart 编程 - 库

编程语言中的库表示一系列例程(一组编程指令)。Dart 有一组内置库,这些库对于存储经常使用的例程很有用。Dart 库包含一组类、常量、函数、typedef、属性和异常。

导入库

导入使库中的组件可用于调用方代码。import 关键字用于实现相同的目的。一个 dart 文件可以有多个 import 语句。

内置的 Dart 库 URI 使用 dart: 方案来引用库。其他库可以使用文件系统路径或 package: 方案来指定其 URI。由包管理器(例如 pub 工具)提供的库使用package: 方案

在 Dart 中导入库的语法如下所示:

import 'URI'

考虑以下代码片段:

import 'dart:io' 
import 'package:lib1/libfile.dart' 

如果只想使用库的一部分,可以选择性地导入该库。相应的语法如下所示:

import 'package: lib1/lib1.dart' show foo, bar;  
// Import only foo and bar. 

import 'package: mylib/mylib.dart' hide foo;  
// Import all names except foo

以下是一些常用的库:

序号 库 & 描述
1

dart:io

用于服务器应用程序的文件、套接字、HTTP 和其他 I/O 支持。此库不适用于基于浏览器的应用程序。此库默认导入。

2

dart:core

每个 Dart 程序的内置类型、集合和其他核心功能。此库会自动导入。

3

dart:math

数学常数和函数,以及随机数生成器。

4

dart:convert

用于在不同数据表示形式(包括 JSON 和 UTF-8)之间转换的编码器和解码器。

5

dart:typed_data

有效处理固定大小数据的列表(例如,无符号 8 字节整数)。

示例:导入和使用库

以下示例导入内置库dart:math。该代码片段调用math库中的sqrt()函数。此函数返回传递给它的数字的平方根。

import 'dart:math'; 
void main() { 
   print("Square root of 36 is: ${sqrt(36)}"); 
}

输出

Square root of 36 is: 6.0

库中的封装

Dart 脚本可以使用下划线 ( _ ) 为标识符添加前缀,以将其组件标记为私有。简单来说,Dart 库可以通过限制外部脚本访问其内容来限制访问。这称为封装。相应的语法如下所示:

语法

_identifier

示例

首先,定义一个包含私有函数的库。

library loggerlib;                            
void _log(msg) {
   print("Log method called in loggerlib msg:$msg");      
} 

接下来,导入库

import 'test.dart' as web; 
void main() { 
   web._log("hello from webloggerlib"); 
} 

以上代码将导致错误。

Unhandled exception: 
No top-level method 'web._log' declared.  
NoSuchMethodError: method not found: 'web._log' 
Receiver: top-level 
Arguments: [...] 
#0 NoSuchMethodError._throwNew (dart:core-patch/errors_patch.dart:184) 
#1 main (file:///C:/Users/Administrator/WebstormProjects/untitled/Assertion.dart:6:3) 
#2 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:261) 
#3 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:148)

创建自定义库

Dart 还允许您使用自己的代码作为库。创建自定义库涉及以下步骤:

步骤 1:声明库

要显式声明库,请使用library 语句。声明库的语法如下所示:

library library_name  
// library contents go here 

步骤 2:关联库

您可以通过两种方式关联库:

  • 在同一目录中
import 'library_name'
  • 从不同的目录
import 'dir/library_name'

示例:自定义库

首先,让我们定义一个自定义库calculator.dart

library calculator_lib;  
import 'dart:math'; 

//import statement after the libaray statement  
int add(int firstNumber,int secondNumber){ 
   print("inside add method of Calculator Library ") ; 
   return firstNumber+secondNumber; 
}  
int modulus(int firstNumber,int secondNumber){ 
   print("inside modulus method of Calculator Library ") ; 
   return firstNumber%secondNumber; 
}  
int random(int no){ 
   return new Random().nextInt(no); 
}

接下来,我们将导入库:

import 'calculator.dart';  
void main() {
   var num1 = 10; 
   var num2 = 20; 
   var sum = add(num1,num2); 
   var mod = modulus(num1,num2); 
   var r = random(10);  
   
   print("$num1 + $num2 = $sum"); 
   print("$num1 % $num2= $mod"); 
   print("random no $r"); 
} 

程序应产生以下输出

inside add method of Calculator Library  
inside modulus method of Calculator Library  
10 + 20 = 30 
10 % 20= 10 
random no 0 

库前缀

如果导入两个具有冲突标识符的库,则可以为一个或两个库指定前缀。使用'as'关键字指定前缀。相应的语法如下所示:

语法

import 'library_uri' as prefix

示例

首先,让我们定义一个库:loggerlib.dart

library loggerlib;  
void log(msg){ 
   print("Log method called in loggerlib msg:$msg");
}   

接下来,我们将定义另一个库:webloggerlib.dart

library webloggerlib; 
void log(msg){ 
   print("Log method called in webloggerlib msg:$msg"); 
} 

最后,我们将使用前缀导入库。

import 'loggerlib.dart'; 
import 'webloggerlib.dart' as web;  

// prefix avoids function name clashes 
void main(){ 
   log("hello from loggerlib"); 
   web.log("hello from webloggerlib"); 
} 

它将产生以下输出 -

Log method called in loggerlib msg:hello from loggerlib 
Log method called in webloggerlib msg:hello from webloggerlib 

Dart 编程 - 异步

异步操作在一个线程中执行,与应用程序线程分离。当应用程序调用方法异步执行操作时,应用程序可以继续执行,而异步方法执行其任务。

示例

让我们举一个例子来理解这个概念。在这里,程序使用IO 库接受用户输入。

import 'dart:io'; 
void main() { 
   print("Enter your name :");            
   
   // prompt for user input 
   String name = stdin.readLineSync();  
   
   // this is a synchronous method that reads user input 
   print("Hello Mr. ${name}"); 
   print("End of main"); 
} 

readLineSync()是一个同步方法。这意味着,在readLineSync()函数调用之后的所有指令的执行将被阻塞,直到readLineSync()方法完成执行。

stdin.readLineSync等待输入。它会停止执行并不会继续执行任何操作,直到它收到用户的输入。

以上示例将产生以下输出

Enter your name :     
Tom                   

// reads user input  
Hello Mr. Tom 
End of main

在计算中,当某个操作在继续执行之前等待事件发生时,我们称之为同步。这种方法的一个缺点是,如果代码的一部分执行时间过长,则后续的代码块,即使不相关,也会被阻止执行。考虑一个必须响应多个资源请求的 Web 服务器。

同步执行模型将阻塞所有其他用户的请求,直到它完成当前请求的处理。在这种情况下,例如 Web 服务器,每个请求都必须独立于其他请求。这意味着,Web 服务器不应该等待当前请求完成执行,然后再响应其他用户的请求。

简单来说,它应该在完成先前用户的请求之前接受新用户的请求。这称为异步。异步编程基本上意味着没有等待或非阻塞编程模型。dart:async包有助于在 Dart 脚本中实现异步编程块。

示例

以下示例更好地说明了异步块的功能。

步骤 1 - 创建一个contact.txt文件,如下所示将其保存在当前项目中的 data 文件夹中。

1, Tom 
2, John 
3, Tim 
4, Jane 

步骤 2 - 编写一个程序,在不阻塞应用程序其他部分的情况下读取文件。

import "dart:async"; 
import "dart:io";  

void main(){ 
   File file = new File( Directory.current.path+"\\data\\contact.txt"); 
   Future<String> f = file.readAsString();  
  
   // returns a futrue, this is Async method 
   f.then((data)=>print(data));  
   
   // once file is read , call back method is invoked  
   print("End of main");  
   // this get printed first, showing fileReading is non blocking or async 
}

此程序的输出如下所示:

End of main 
1, Tom 
2, John 
3, Tim 
4, Jan

"end of main" 首先执行,而脚本继续读取文件。Future类(dart:async的一部分)用于在异步任务完成后获取计算结果。然后使用此Future值在计算完成后执行某些操作。

读取操作完成后,执行控制权将转移到"then()"内。这是因为读取操作可能需要更多时间,因此它不想阻塞程序的其他部分。

Dart Future

Dart 社区将Future定义为“一种在将来某个时间获取值的方法”。简单来说,Future 对象是一种表示由表达式返回的值的机制,该表达式的执行将在以后的某个时间点完成。Dart 的许多内置类在调用异步方法时都会返回Future

Dart 是一种单线程编程语言。如果任何代码阻塞执行线程(例如,通过等待耗时操作或阻塞 I/O),则程序实际上会冻结。

异步操作允许您的程序在不发生阻塞的情况下运行。Dart 使用Future 对象来表示异步操作。

Dart 编程 - 并发

并发是同时执行多个指令序列。它涉及同时执行多个任务。

Dart 使用Isolate作为并行执行工作的工具。dart:isolate包是 Dart 的解决方案,用于获取单线程 Dart 代码并允许应用程序更好地利用可用的硬件。

Isolate顾名思义,是运行代码的隔离单元。它们之间传递数据的唯一方法是通过传递消息,就像您在客户端和服务器之间传递消息的方式一样。Isolate帮助程序利用多核微处理器。

示例

让我们举一个例子来更好地理解这个概念。

import 'dart:isolate';  
void foo(var message){ 
   print('execution from foo ... the message is :${message}'); 
}  
void main(){ 
   Isolate.spawn(foo,'Hello!!'); 
   Isolate.spawn(foo,'Greetings!!'); 
   Isolate.spawn(foo,'Welcome!!'); 
   
   print('execution from main1'); 
   print('execution from main2'); 
   print('execution from main3'); 
}

在这里,Isolate类的spawn方法有助于与代码的其余部分并行运行函数foospawn函数接受两个参数:

  • 要生成的函数,以及
  • 将传递给生成的函数的对象。

如果没有要传递给生成的函数的对象,可以传递 NULL 值。

这两个函数(foo 和 main)不一定每次都按相同的顺序运行。无法保证foo何时执行以及main()何时执行。每次运行时输出将不同。

输出 1

execution from main1 
execution from main2 
execution from main3 
execution from foo ... the message is :Hello!! 

输出 2

execution from main1 
execution from main2 
execution from main3 
execution from foo ... the message is :Welcome!! 
execution from foo ... the message is :Hello!! 
execution from foo ... the message is :Greetings!! 

从输出中,我们可以得出结论,Dart 代码可以从正在运行的代码中生成新的Isolate,就像 Java 或 C# 代码可以启动新线程一样。

Isolate与线程的不同之处在于,Isolate具有自己的内存。无法在Isolate之间共享变量——Isolate之间通信的唯一方法是通过消息传递。

注意 - 对于不同的硬件和操作系统配置,以上输出将有所不同。

Isolate 与 Future

异步执行复杂的计算工作对于确保应用程序的响应性非常重要。Dart Future是一种在异步任务完成后检索其值的机制,而Dart Isolate是一种用于抽象化并行性和在实践中以高级别实现它的工具。

Dart 编程 - 单元测试

单元测试涉及测试应用程序的每个单独单元。它帮助开发人员测试小功能,而无需运行整个复杂的应用程序。

名为“test”的 Dart外部库提供了一种编写和运行单元测试的标准方法。

Dart 单元测试涉及以下步骤:

步骤 1:安装“test”包

要在当前项目中安装第三方包,您需要pubspec.yaml文件。要安装test 包,请首先在pubspec.yaml文件中进行以下条目:

dependencies: 
test:

进行条目后,右键单击pubspec.yaml文件并获取依赖项。它将安装“test”包。以下是WebStorm编辑器中相同的屏幕截图。

Unit Testing

也可以从命令行安装包。在终端中键入以下内容:

pub get

步骤 2:导入“test”包

import "package:test/test.dart";

步骤 3 编写测试

测试使用顶级函数test()指定,而测试断言使用expect()函数进行。要使用这些方法,应将其安装为pub依赖项。

语法

test("Description of the test ", () {  
   expect(actualValue , matchingValue) 
});

group()函数可用于对测试进行分组。每个组的描述都会添加到其测试描述的开头。

语法

group("some_Group_Name", () { 
   test("test_name_1", () { 
      expect(actual, equals(exptected)); 
   });  
   test("test_name_2", () { 
      expect(actual, equals(expected)); 
   }); 
}) 

示例 1:通过测试

以下示例定义了一个方法Add()。此方法接受两个整数值并返回一个表示的整数。要测试此add()方法:

步骤 1 - 如下所示导入test包。

步骤 2 - 使用test()函数定义测试。在这里,test()函数使用expect()函数强制执行断言。

import 'package:test/test.dart';      
// Import the test package 

int Add(int x,int y)                  
// Function to be tested { 
   return x+y; 
}  
void main() { 
   // Define the test 
   test("test to check add method",(){  
      // Arrange 
      var expected = 30; 
      
      // Act 
      var actual = Add(10,20); 
      
      // Asset 
      expect(actual,expected); 
   }); 
}

它应产生以下输出

00:00 +0: test to check add method 
00:00 +1: All tests passed! 

示例 2:失败测试

下面定义的subtract()方法存在逻辑错误。以下测试验证了这一点。

import 'package:test/test.dart'; 
int Add(int x,int y){ 
   return x+y; 
}
int Sub(int x,int y){ 
   return x-y-1; 
}  
void main(){ 
   test('test to check sub',(){ 
      var expected = 10;   
      // Arrange 
      
      var actual = Sub(30,20);  
      // Act 
      
      expect(actual,expected);  
      // Assert 
   }); 
   test("test to check add method",(){ 
      var expected = 30;   
      // Arrange 
      
      var actual = Add(10,20);  
      // Act 
      
      expect(actual,expected);  
      // Asset 
   }); 
}

输出 - 函数add()的测试用例通过,但subtract()的测试失败,如下所示。

00:00 +0: test to check sub 
00:00 +0 -1: test to check sub 
Expected: <10> 
Actual: <9> 
package:test  expect 
bin\Test123.dart 18:5  main.<fn> 
   
00:00 +0 -1: test to check add method 
00:00 +1 -1: Some tests failed.  
Unhandled exception: 
Dummy exception to set exit code. 
#0  _rootHandleUncaughtError.<anonymous closure> (dart:async/zone.dart:938) 
#1  _microtaskLoop (dart:async/schedule_microtask.dart:41)
#2  _startMicrotaskLoop (dart:async/schedule_microtask.dart:50) 
#3  _Timer._runTimers (dart:isolate-patch/timer_impl.dart:394) 
#4  _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:414) 
#5  _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:148) 

分组测试用例

您可以对测试用例进行分组,以便为您的测试代码添加更多含义。如果您有许多测试用例,这有助于编写更简洁的代码。

在给定的代码中,我们正在为split()函数和trim函数编写测试用例。因此,我们从逻辑上对这些测试用例进行分组并将其称为String

示例

import "package:test/test.dart"; 
void main() { 
   group("String", () { 
      test("test on split() method of string class", () { 
         var string = "foo,bar,baz"; 
         expect(string.split(","), equals(["foo", "bar", "baz"])); 
      }); 
      test("test on trim() method of string class", () { 
         var string = "  foo "; 
         expect(string.trim(), equals("foo")); 
      }); 
   }); 
} 

输出 - 输出将为每个测试用例追加组名称,如下所示:

00:00 +0: String test on split() method of string class 
00:00 +1: String test on trim() method of string class 
00:00 +2: All tests passed

Dart 编程 - HTML DOM

每个网页都位于可以视为对象的浏览器窗口内。

Document 对象表示在该窗口中显示的 HTML 文档。Document 对象具有各种属性,这些属性引用其他对象,允许访问和修改文档内容。

访问和修改文档内容的方式称为**文档对象模型**,或**DOM**。对象以层次结构组织。这种层次结构适用于Web文档中对象的组织。

  • **Window** − 层次结构的顶层。它是对象层次结构的最外层元素。

  • **Document** − 每个加载到窗口中的HTML文档都成为一个文档对象。文档包含页面的内容。

  • **Elements** − 表示网页上的内容。例如文本框、页面标题等。

  • **Nodes** − 通常是元素,但也可以是属性、文本、注释和其他DOM类型。

以下是一些重要DOM对象的简单层次结构:

HTML DOM

Dart提供**dart:html**库来操作DOM中的对象和元素。基于控制台的应用程序无法使用**dart:html**库。要在Web应用程序中使用HTML库,请导入**dart:html**:

import 'dart:html';

接下来,我们将在下一节中讨论一些**DOM操作**。

查找DOM元素

**dart:html**库提供**querySelector**函数来搜索DOM中的元素。

Element querySelector(String selectors);

**querySelector()**函数返回与指定选择器组匹配的第一个元素。**"selectors"**应使用如下所示的CSS选择器语法表示字符串

var element1 = document.querySelector('.className'); 
var element2 = document.querySelector('#id'); 

示例:操作DOM

在Webstorm IDE中按照以下步骤操作:

**步骤1** − 文件->新建项目→在位置处,将项目名称指定为**DemoWebApp**。

Demowebapp

**步骤2** − 在“生成示例内容”部分,选择**SimpleWebApplication**。

Create

它将创建一个示例项目**DemoWebApp**。有一个**pubspec.yaml**文件包含需要下载的依赖项。

name: 'DemoWebApp' 
version: 0.0.1 
description: An absolute bare-bones web app. 

#author: Your Name <[email protected]> 
#homepage: https://www.example.com  
environment:   
   sdk: '>=1.0.0 <2.0.0'  
dependencies:   
   browser: '>=0.10.0 <0.11.0'   dart_to_js_script_rewriter: '^1.0.1'  
transformers: 
- dart_to_js_script_rewriter 

如果您已连接到网络,则这些文件将自动下载,否则您可以右键单击**pubspec.yaml**并获取依赖项。

Pub Get Dependencies

在web文件夹中,您将找到三个文件:**Index.html、main.dart**和**style.css**

Index.html

<!DOCTYPE html>   
<html> 
   <head>     
      <meta charset = "utf-8">     
      <meta http-equiv = "X-UA-Compatible" content = "IE = edge">     
      <meta name = "viewport" content = "width = device-width, initial-scale = 1.0">
      <meta name = "scaffolded-by" content = "https://github.com/google/stagehand">
      <title>DemoWebApp</title>     
      <link rel = "stylesheet" href = "styles.css">     
      <script defer src = "main.dart" type = "application/dart"></script>
      <script defer src = "packages/browser/dart.js"></script> 
   </head>
   
   <body>   
      <h1>
         <div id = "output"></div> 
      </h1>  
   </body> 
</html> 

Main.dart

import 'dart:html';  
void main() {   
   querySelector('#output').text = 'Your Dart web dom app is running!!!.'; 
} 

运行**index.html**文件;您将在屏幕上看到以下输出。

Demo Web App

事件处理

**dart:html**库为DOM元素提供了**onClick**事件。语法显示了元素如何处理点击事件流。

querySelector('#Id').onClick.listen(eventHanlderFunction); 

**querySelector()**函数从给定的DOM中返回元素,而**onClick.listen()**将获取一个**eventHandler**方法,该方法将在触发点击事件时被调用。**eventHandler**的语法如下所示:

void eventHanlderFunction (MouseEvent event){ } 

现在让我们举一个例子来理解Dart中事件处理的概念。

TestEvent.html

<!DOCTYPE html> 
<html> 
   <head> 
      <meta charset = "utf-8"> 
      <meta http-equiv = "X-UA-Compatible" content = "IE = edge"> 
      <meta name = "viewport" content = "width = device-width, initial-scale = 1.0"> 
      <meta name = "scaffolded-by" content ="https://github.com/google/stagehand"> 
      <title>DemoWebApp</title> 
      <link rel = "stylesheet" href = "styles.css"> 
      <script defer src = "TestEvent.dart" type="application/dart"></script> 
      <script defer src = "packages/browser/dart.js"></script> 
   </head> 
   
   <body> 
      <div id = "output"></div> 
      <h1> 
         <div> 
            Enter you name : <input type = "text" id = "txtName"> 
            <input type = "button" id = "btnWish" value="Wish"> 
         </div> 
      </h1> 
      <h2 id = "display"></h2> 
   </body>
   
</html>

TestEvent.dart

import 'dart:html'; 
void main() { 
   querySelector('#btnWish').onClick.listen(wishHandler); 
}  
void wishHandler(MouseEvent event){ 
   String name = (querySelector('#txtName')  as InputElement).value; 
   querySelector('#display').text = 'Hello Mr.'+ name; 
}

输出

Output
广告